“Gölgeli” bir Java bağımlılığı nedir?


74

JVM geliştiricisi burada. Son zamanlarda IRC sohbet odalarında ve hatta " gölgeli " Java kitaplıkları hakkında kendi ofisimde şaka yapan birini gördüm . Kullanımın içeriği şöyle olacaktır:

" Böyle ve böylece XYZ için" gölgeli "bir istemci var. "

Mükemmel bir örnek HBase için şu Jira sorunudur : " Gölgeli bağımlılıkları olan bir müşteri eserini yayınla "

Öyleyse soruyorum: Gölgeli bir JAR nedir, “gölgeli” olmak ne demektir?

Yanıtlar:


86

Bağımlılıkların gölgelenmesi , kendi kodunuzun yanında topladığınız özel bir kopya oluşturmak için bağımlılıkları dahil etme ve yeniden adlandırma işlemidir (bu nedenle sınıfları ve etkilenen sınıfları ve kaynakları yeniden yerleştirme) .

Konsept genellikle über kavanozlarla (aka yağ kavanozları ) ilişkilendirilir.

Bu terimle ilgili bazı karışıklıklar var , çünkü tek bir ad altında 2 şeyi yapan maven gölge eklentisi :

Bu eklenti, artefaktı, bağımlılıkları da dahil olmak üzere bir uber kavanoza koyma ve bazı bağımlılıkların paketlerini gölgelendirme - yani yeniden adlandırma - kabiliyeti sağlar .

Böylece gölgelendirme kısmı aslında isteğe bağlıdır: Eklenti, kavanoza (yağ kavanozu) bağımlılıkları dahil etmeyi ve isteğe bağlı olarak (gölge) bağımlılıkları yeniden adlandırmayı sağlar .

Başka bir kaynak eklemek :

Bir kütüphaneyi gölgelendirmek için, söz konusu kütüphanenin içerik dosyalarını almak, kendi kavanozunuza koymak ve paketini değiştirmek . Bu, farklı bir pakete yerleştirmeden, kendi kütüphanenizdeki kitaplık dosyalarını yanınızda taşıyarak paketlemekten farklıdır.

Teknik olarak konuşursak, bağımlılıklar gölgelendirilir. Ancak, gölgeli bir şişeli-gölgeli bağımlılıklara "gölgeli kavanoz" olarak atıfta bulunmak yaygındır ve bu kavanoz başka bir sistem için bir müşteri ise, "gölgeli müşteri" olarak adlandırılabilir.

İşte sorunuza bağladığınız HBase için Jira sayısının başlığı :

Gölgeli bağımlılıkları olan bir istemci eserini yayınlayın

Yani bu yazıda, 2 kavramı, onları birbirine karıştırmadan sunmaya çalışıyorum.

İyi

Uber-jar'lar genellikle bir uygulamayı tek bir dosya olarak göndermek için kullanılır (dağıtılmasını ve çalıştırılmasını kolaylaştırır). Diğer uygulamaların (bu kitaplıkların farklı sürümlerini kullanabilecekleri) kullandıkları çatışmaları önlemek için, kitaplıkların bazılarının (veya hepsinin) gölgeli olmaları ile birlikte gölgelendirilmesi için de kullanılabilirler.

Über kavanozlarını yapmanın birkaç yolu var, ancak sınıf yer değiştirme özelliği maven-shade-pluginile bir adım daha ileri gidiyor :

Uber JAR, başka bir projenin bağımlılığı olarak tekrar kullanılırsa, doğrudan nesnenin JAR'daki bağımlılık sınıflarından doğrudan dahil edilmesi, sınıf yolundaki yinelenen sınıflar nedeniyle sınıf yükleme çatışmalarına neden olabilir. Bu konuyu ele almak için, bayt kodlarının özel bir kopyasını oluşturmak için gölgeli yapıya dahil edilen sınıflar yerleştirilebilir.

(Tarihsel not: Jar Jar Links , bu yer değiştirme özelliğini daha önce sundu)

Bu sayede, API'nizdeki kütüphanelerden sınıfları göstermediğiniz sürece, kütüphane bağımlılıklarınızı bir uygulama detayı haline getirebilirsiniz .

Diyelim ki bir projem var, DecayingSyncQuantanizersınıf sağlayan ve Apache commons- rng'ye bağlı olan ACME Quantanizer ™ (tabii ki uygun bir şekilde quantanlaştırmak için XorShift1024Star).

Bir uber jar üretmek için shade maven eklentisini kullanırsam ve içeri bakarsam, şu sınıf dosyalarını görürüm:

com/acme/DecayingSyncQuantanizer.class
org/apache/commons/rng/RandomProviderState.class
org/apache/commons/rng/RestorableUniformRandomProvider.class
...
org/apache/commons/rng/core/source64/XorShift1024Star.class
org/apache/commons/rng/core/util/NumberFactory.class

Şimdi sınıf değiştirme özelliğini kullanırsam:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <version>3.0.0</version>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>shade</goal>
      </goals>
      <configuration>
        <relocations>
          <relocation>
            <pattern>org.apache.commons</pattern>
            <shadedPattern>com.acme.shaded.apachecommons</shadedPattern>
          </relocation>
        </relocations>
      </configuration>
    </execution>
  </executions>
</plugin>

Uber-jar içeriği şöyle görünür:

com/acme/DecayingSyncQuantanizer.class
com/acme/shaded/apachecommons/rng/RandomProviderState.class
com/acme/shaded/apachecommons/rng/RestorableUniformRandomProvider.class
...
com/acme/shaded/apachecommons/rng/core/source64/XorShift1024Star.class
com/acme/shaded/apachecommons/rng/core/util/NumberFactory.class

Sadece dosyaları yeniden adlandırmakla kalmaz, yeniden yerleştirilmiş sınıflara referans veren bytecode yazar (yani, kendi sınıflarım ve commons-rng sınıflarım hepsi dönüştürülür).

Ek olarak, Shade eklentisi ayrıca dependency-reduced-pom.xmlgölgeli bağımlılıkların <dependencies>bölümden uzaklaştırıldığı yeni bir POM ( ) üretecektir . Bu, gölgeli kavanozun başka bir projeye bağımlılık olarak kullanılmasına yardımcı olur. Böylece, bu kavanozun yerine bir tane veya her ikisini de (gölgeli kavanoz için bir niteleyici kullanarak) yayınlayabilirsiniz .

Yani bu çok yararlı olabilir ...

Kötü

... ama aynı zamanda bir takım sorunları da beraberinde getiriyor. Tüm bağımlılıkların kavanoz içindeki tek bir "ad alanı" nda toplanması karışıklığa neden olabilir ve gölgelendirme ve kaynaklarla uğraşmayı gerektirir.

Örneğin: sınıf veya paket adlarını içeren kaynak dosyalarıyla nasıl başa çıkılır? Tüm altında yaşayan servis sağlayıcı tanımlayıcıları gibi kaynak dosyalar META-INF/services?

Gölge eklentisi, bu konuda yardımcı olabilecek kaynak transformatörleri sunar :

Çeşitli eserlerdeki sınıfları / kaynakları tek bir JAR'da bir araya getirmek, üst üste binme olmadığı sürece dümdüz ileridir. Aksi takdirde, birkaç JAR'dan kaynakları birleştirmek için bir tür mantık gerekir. Kaynak transformatörleri burada devreye giriyor.

Ancak yine de dağınıktır ve sorunların önceden tahmin edilmesi neredeyse imkansızdır (sorunları sıklıkla üretimdeki zor yoldan keşfedersiniz). Neden yağ kavanozlarını bıraktığımızı görün .

Sonuçta, bağımsız bir uygulama / hizmet olarak yağ kavanozunu yerleştirmek hala çok yaygındır, sadece gotcha'ların farkında olmanız ve bazılarının gölgelendirme veya başka hilelerden haberdar olmanız gerekir .

Çirkin

Çok daha zor konular var (hata ayıklama, test edilebilirlik, OSGi ve egzotik sınıf yükleyicileriyle uyumluluk ...).

Fakat daha önemlisi, bir kütüphane ürettiğinizde, kontrol edebileceğinizi düşündüğünüz çeşitli konular şimdi daha da karmaşık bir hale geliyor, çünkü kavanozunuz birçok farklı bağlamda kullanılacak (bağımsız bir uygulama / hizmet olarak uyguladığınız yağ kavanozunun aksine) kontrollü bir ortamda).

Örneğin, ElasticSearch, sevk ettikleri kavanozlardaki bazı bağımlılıkları gölgelemek için kullanılır, ancak bunu yapmayı bırakmaya karar verdiler :

Versiyon 2.0'dan önce, Elasticsearch, aynı eserde gölgeli ve paketlenmiş bazı (hepsi değil) ortak bağımlılıklara sahip bir JAR olarak sağlandı. Bu, Guava, Joda, Jackson, vb. Modüllerin sürüm çatışmalarını önlemek için Elasticsearch'ü kendi uygulamalarına yerleştiren Java kullanıcılarının, elbette, yine de çatışmalara neden olabilecek, Lucene gibi diğer gölgesiz bağımlılıkların bir listesi vardı.
Ne yazık ki, gölgelendirme, bazı insanlar için problem yaratırken bazılarına problem çözen karmaşık ve hataya açık bir süreçtir. Gölgeleme, geliştiricilerin ve eklenti yazarlarının kodları doğru bir şekilde yazmasını ve hata ayıklamasını sağlar çünkü paketler oluşturma sırasında yeniden adlandırılır. Sonunda, Elasticsearch'ü gölgesiz olarak test eder, sonra gölgeli kavanozu gönderirdik ve test etmediğimiz hiçbir şeyi göndermeyi sevmiyoruz.
Elasticsearch'ü 2,0 yaşından itibaren gölgelendirmeden göndermeye karar verdik.

Lütfen onların da gölgeli kavanozlara değil gölgeli bağımlılıklara atıfta bulunduklarına dikkat edin.


1
Bunu açıklamak için zaman ayırdığınız için teşekkür ederiz. Maven gölge eklentisinin resmi dokümantasyonu tamamen yetersizdir ve bunların hiçbirini tartışmaz, hatta "uber kavanozu" nu tanımlamak için zahmete girmez. Bu belgeler geniş ve işe yaramaz. Yazmanız yararlıdır.
Cheeso

Mükemmel bir açıklama, resmi belgelere dahil edilmesi gerektiğini düşünüyorum
Adelin

7

En azından maven kullanırken gölgeli kavanozlar oluşturmaktan gerçekten sorumlu olan yazılımın yardımıyla soruyu cevaplayayım.

Alındığı Apache Maven Gölge Eklenti ana sayfasında:

Bu eklenti, artefaktı, bağımlılıkları da dahil olmak üzere bir uber kavanoza koyma ve bazı bağımlılıkların paketlerini gölgelendirme - yani yeniden adlandırma - kabiliyeti sağlar.

Gölgeli bir kavanoz aka uber-jar aka yağ kavanoz, varsayılan olarak, Java uygulamasını çalıştırmak için gereken her bağımlılığı içerecektir, böylece sınıf yolunda ilave bir bağımlılık olması gerekmez. Uygulamanızı çalıştırmak için yalnızca doğru Java sürümüne ihtiyacınız var. Gölgeli bir kavanoz, yerleştirme / sınıf yolu problemlerini önlemeye yardımcı olacaktır, ancak orijinal uygulama kavanozundan çok daha büyük olacaktır ve kavanoz cehenneminden kaçınmanıza yardımcı olmayacaktır.


1
Korkarım bu cevap eksik: şişman / über kavanozların ne olduğunu açıklıyor, ancak gölgelendirme kısmını açıklamıyor . Ve evet, gölgelemenin "kavanoz cehennemi" ne (bu cevabın son kısmını yanlış yapan) yardım etmesi gerekiyor. Bu nedenle, bazı seviyelerde yararlıdır, ancak kargaşaya katkıda bulunur: - /
Hugues M.,

1
@HuguesMoreau Yanıtımda% 100 tamamlanmış olamayabilirim, ama yine de üstesinden gelmek istediğim şeyi getirdi. Kayıp kısmı masaya getirdiğiniz için teşekkürler. Gölgelendirme, cehennem cehenneminden kaçınmayacak, kastettiğim ve yazdığım şeydi, ancak elinizde bazı problemleri çözmenize izin verecek bazı araçlar verecek, ancak otomatik değil. En azından tamam demek istediğimi okuduysanız ve yorumladıysanız bu son kısmı yapar. :)
Jesko R.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.