Một phụ thuộc Java bóng mờ là gì?


75

Nhà phát triển JVM tại đây. Gần đây tôi đã thấy những lời nói đùa trên các phòng chat IRC và ngay cả trong văn phòng của riêng tôi về cái gọi là thư viện Java " bóng mờ ". Bối cảnh của việc sử dụng sẽ là một cái gì đó như:

" Như vậy và do đó cung cấp một ứng dụng khách" bóng mờ "cho XYZ. "

Ví dụ hoàn hảo là vấn đề Jira này cho HBase : " Xuất bản một tạo phẩm của khách hàng với các phụ thuộc được tô bóng "

Vì vậy, tôi hỏi: JAR bóng mờ là gì, "bóng mờ" nghĩa là gì?

Câu trả lời:


88

Tạo bóng phụ thuộc là quá trình bao gồm và đổi tên các phụ thuộc (do đó di chuyển các lớp và viết lại mã nguồn & tài nguyên bị ảnh hưởng) để tạo một bản sao riêng mà bạn gói cùng với mã của riêng bạn .

Khái niệm này thường được liên kết với uber-jars (còn gọi là lọ chất béo ).

Có một số nhầm lẫn về thuật ngữ này , vì plugin maven bóng râm, mà dưới tên duy nhất đó có 2 điều (trích dẫn trang riêng của họ):

Plugin này cung cấp khả năng đóng gói tạo phẩm trong một uber-jar, bao gồm cả các phụ thuộc của nó và để tạo bóng - tức là đổi tên - các gói của một số phụ thuộc.

Vì vậy, phần tô bóng thực sự là tùy chọn: plugin cho phép bao gồm các phụ thuộc trong jar của bạn (jar chất béo) và tùy chọn đổi tên (bóng) phụ thuộc .

Thêm một nguồn khác :

Để che thư viện là lấy các tệp nội dung của thư viện nói trên, đặt chúng vào bình riêng của bạn và thay đổi gói của chúng . Điều này khác với việc đóng gói chỉ đơn giản là vận chuyển các tệp thư viện bên cạnh bình của riêng bạn mà không chuyển chúng sang một gói khác.

Về mặt kỹ thuật, sự phụ thuộc được tô bóng. Nhưng thông thường gọi một lọ chứa chất béo có phụ thuộc bóng mờ là "bình được tô bóng" và nếu bình đó là máy khách cho một hệ thống khác, thì nó có thể được gọi là "máy khách được tô bóng".

Đây là tiêu đề của vấn đề Jira cho HBase mà bạn đã liên kết trong câu hỏi của mình:

Xuất bản một tạo phẩm của khách hàng với các phụ thuộc được tô bóng

Vì vậy, trong bài viết này, tôi đang cố gắng trình bày 2 khái niệm mà không kết hợp chúng.

Tốt

Uber-jar thường được sử dụng để gửi một ứng dụng dưới dạng một tệp duy nhất (giúp dễ dàng triển khai và chạy). Chúng cũng có thể được sử dụng để vận chuyển các thư viện cùng với một số (hoặc tất cả) các phần phụ thuộc của chúng được tô bóng , để tránh xung đột khi được sử dụng bởi các ứng dụng khác (có thể sử dụng các phiên bản khác nhau của các thư viện đó).

Có một số cách để xây dựng uber-jars, nhưng maven-shade-plugintiến thêm một bước với tính năng di chuyển lớp :

Nếu JAR uber được sử dụng lại như một phụ thuộc của một số dự án khác, bao gồm trực tiếp các lớp từ các phụ thuộc của tạo phẩm trong Juber uber có thể gây ra xung đột tải lớp do các lớp trùng lặp trên đường dẫn lớp. Để giải quyết vấn đề này, người ta có thể định vị lại các lớp được bao gồm trong tạo phẩm được tô bóng để tạo một bản sao riêng của mã byte của chúng.

(Ghi chú lịch sử: Jar Jar Links đã cung cấp tính năng di dời trước đó)

Vì vậy, với điều này, bạn có thể làm cho các phụ thuộc thư viện của mình trở thành một chi tiết triển khai , trừ khi bạn trưng ra các lớp từ các thư viện đó trong API của mình.

Giả sử tôi có một dự án, ACME Quantanizer ™, cung cấp DecayingSyncQuantanizerlớp và phụ thuộc vào Apache commons-rng (vì tất nhiên để định lượng chính xác bạn cần một XorShift1024Star, duh).

Nếu tôi sử dụng plugin bóng râm để tạo uber-jar và tôi nhìn vào bên trong, tôi thấy các tệp lớp này:

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

Bây giờ nếu tôi sử dụng tính năng chuyển vị trí lớp:

<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>

Nội dung của uber-jar trông như thế này:

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

Nó không chỉ đổi tên các tệp, nó viết lại mã byte mà tham chiếu các lớp được di dời (vì vậy, các lớp và lớp commons-rng của riêng tôi đều được chuyển đổi).

Ngoài ra, plugin Shadow cũng sẽ tạo ra một POM ( dependency-reduced-pom.xml) mới trong đó các phần phụ thuộc được tô bóng được loại bỏ khỏi <dependencies>phần này. Điều này giúp sử dụng bình tô bóng làm phụ thuộc cho một dự án khác. Vì vậy, bạn có thể xuất bản bình đó thay vì cơ sở hoặc cả hai (sử dụng vòng loại cho bình được tô bóng).

Vì vậy, nó có thể rất hữu ích ...

Những người xấu

... nhưng nó cũng đặt ra một số vấn đề. Tổng hợp tất cả các phụ thuộc vào một "không gian tên" duy nhất trong tệp có thể trở nên lộn xộn và yêu cầu tạo bóng & làm rối với các tài nguyên.

Ví dụ: làm thế nào để đối phó với các tệp tài nguyên bao gồm tên lớp hoặc tên gói? Các tệp tài nguyên như mô tả nhà cung cấp dịch vụ mà tất cả đều sống theo META-INF/services?

Plugin bóng râm cung cấp các biến áp tài nguyên có thể giúp với điều đó:

Tổng hợp các lớp / tài nguyên từ một số vật phẩm vào một JAR uber là thẳng về phía trước miễn là không có sự chồng chéo. Mặt khác, một số loại logic để hợp nhất các tài nguyên từ một số JAR là bắt buộc. Đây là nơi máy biến áp tài nguyên đá vào.

Nhưng nó vẫn còn lộn xộn, và các vấn đề gần như không thể lường trước được (khá thường xuyên bạn phát hiện ra các vấn đề một cách khó khăn trong sản xuất). Xem tại sao-chúng tôi dừng lại xây dựng-chất béo-lọ .

Nói chung, việc triển khai một lọ mỡ như một ứng dụng / dịch vụ độc lập vẫn còn rất phổ biến, bạn chỉ cần lưu ý về vấn đề này và đối với một số trong những người bạn có thể cần tô bóng hoặc các thủ thuật khác.

Xấu xí

Có nhiều vấn đề khó khăn hơn (gỡ lỗi, kiểm tra, tương thích với OSGi & trình nạp lớp kỳ lạ ...).

Nhưng quan trọng hơn, khi bạn sản xuất một thư viện, các vấn đề khác nhau mà bạn nghĩ rằng bạn có thể kiểm soát giờ trở nên phức tạp hơn nhiều, bởi vì bình của bạn sẽ được sử dụng trong nhiều bối cảnh khác nhau (không giống như một bình chứa chất béo mà bạn triển khai như một ứng dụng / dịch vụ độc lập trong một môi trường được kiểm soát).

Ví dụ: ElasticSearch được sử dụng để che giấu một số phụ thuộc trong các lọ mà họ vận chuyển, nhưng họ đã quyết định ngừng làm điều đó :

Trước phiên bản 2.0, Elaticsearch đã được cung cấp dưới dạng JAR với một số (nhưng không phải tất cả) các phụ thuộc chung được tô bóng và đóng gói trong cùng một vật phẩm. Điều này đã giúp người dùng Java nhúng Elaticsearch vào các ứng dụng của riêng họ để tránh xung đột phiên bản của các mô-đun như Guava, Joda, Jackson, v.v. Tất nhiên, vẫn còn một danh sách các phụ thuộc không bị che khuất khác như Lucene vẫn có thể gây ra xung đột.
Thật không may, shading là một quá trình dễ bị lỗi và phức tạp, giải quyết vấn đề cho một số người trong khi tạo ra vấn đề cho những người khác. Shading làm cho các nhà phát triển và tác giả plugin rất khó viết và gỡ lỗi mã đúng cách vì các gói được đổi tên trong quá trình xây dựng. Cuối cùng, chúng tôi đã sử dụng để kiểm tra Elaticsearch không bóng mờ sau đó gửi bình bóng mờ và chúng tôi không muốn gửi bất cứ thứ gì mà chúng tôi không thử nghiệm.
Chúng tôi đã quyết định gửi Elaticsearch mà không cần tô màu từ 2.0 trở đi.

Xin lưu ý rằng họ cũng đề cập đến các phụ thuộc được tô bóng , không được tô bóng


1
Cảm ơn đã dành thời gian để giải thích điều này. Tài liệu chính thức của plugin maven bóng râm hoàn toàn không đầy đủ và không thảo luận về bất kỳ điều gì trong số này, hoặc thậm chí không bận tâm đến việc định nghĩa "uber jar". Tài liệu đó là khó hiểu và vô dụng. Viết của bạn là hữu ích.
Cheeso

Giải thích tuyệt vời, tôi nghĩ rằng nó nên được đưa vào các tài liệu chính thức
Adelin

7

Hãy để tôi trả lời câu hỏi với sự trợ giúp của phần mềm thực sự chịu trách nhiệm tạo ra các lọ bóng mờ ... ít nhất là khi sử dụng maven.

Lấy từ trang chủ Plugin Apache Maven Shadow :

Plugin này cung cấp khả năng đóng gói tạo phẩm trong một uber-jar, bao gồm cả các phụ thuộc của nó và để tạo bóng - tức là đổi tên - các gói của một số phụ thuộc.

Một jar shaded aka uber-jar aka fat jar theo mặc định sẽ chứa mọi phụ thuộc được yêu cầu để chạy ứng dụng Java để không có phụ thuộc bổ sung nào được yêu cầu phải có trong đường dẫn lớp. Bạn chỉ cần phiên bản Java chính xác để chạy ứng dụng của bạn. Một jar được tô bóng sẽ giúp tránh các vấn đề về triển khai / classpath, nhưng nó sẽ lớn hơn nhiều so với jar ứng dụng ban đầu và nó sẽ không giúp bạn tránh được jar jar.


1
Sợ câu trả lời này không đầy đủ: nó giải thích những cái lọ chất béo / uber là gì, nhưng không giải thích được phần bóng mờ . Và đúng vậy, shading được cho là 100% để giúp với "jar hell" (điều này làm cho phần cuối của câu trả lời không chính xác). Vì vậy, nó hữu ích ở một số cấp độ nhưng làm tăng thêm sự nhầm lẫn: - /
Hugues M.

1
@HuguesMoreau Tôi có thể không hoàn thành 100% trong phản hồi của mình, nhưng nó vẫn mang lại điểm tôi muốn thực hiện. Cảm ơn đã mang phần còn thiếu lên bàn. Shading sẽ không tránh được địa ngục, đó là những gì tôi muốn nói và đã viết, nhưng nó sẽ cung cấp cho bạn một số công cụ giúp bạn giải quyết một số vấn đề của nó, nhưng nó không tự động. Điều này làm cho phần cuối cùng nếu đọc và diễn giải theo cách tôi muốn nói, ít nhất là ok. :)
Jesko R.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.