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-plugin
tiế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 DecayingSyncQuantanizer
lớ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