Maven-bóng-plugin được sử dụng để làm gì và tại sao bạn muốn định vị lại các gói Java?


281

Tôi đã tìm thấy maven-bóng-plugin đang được sử dụng trong tệp pom.xml của ai đó. Tôi chưa bao giờ sử dụng maven-bóng-plugin trước đây (và tôi là Maven n00b) vì vậy tôi đã cố gắng hiểu lý do sử dụng cái này và những gì nó làm.

Tôi đã xem các tài liệu Maven , tuy nhiên tôi không thể hiểu được tuyên bố này:

"Plugin này cung cấp khả năng đóng gói cổ vật 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."

Các tài liệu trên trang không có vẻ rất thân thiện với người mới.

Một "bình uber là gì?" Tại sao ai đó muốn làm cho một? Điểm đổi tên của các gói phụ thuộc là gì? Tôi đã cố gắng xem qua các ví dụ trên trang apache maven-bóng-plugin, chẳng hạn như "Chọn nội dung cho Uber Jar", nhưng tôi vẫn không thể hiểu những gì đang được thực hiện với "bóng mờ".

Bất kỳ con trỏ đến ví dụ minh họa / trường hợp sử dụng (với một lời giải thích tại sao cần phải tô bóng trong trường hợp này - vấn đề là nó giải quyết vấn đề gì) sẽ được đánh giá cao. Cuối cùng, khi nào tôi nên sử dụng plugin maven-bóng-plugin?


16
Đối với việc đặt tên "uber jar", tôi có mối liên hệ duy nhất với tiếng Đức, trong đó "über" có nghĩa là "kết thúc". Cùng nhau theo nghĩa đen, nó có nghĩa là "bình quá tất cả các lọ khác". "Shading" giống như "phân bổ lại gói" cần thiết cho các lớp hoặc tài nguyên va chạm.
dma_k

1
s/reallocation/relocation/trong nhận xét trên.
Christopher Schultz

12
Chiếc bình uber giống như một chiếc nhẫn: Một chiếc bình để cai trị tất cả, một chiếc bình để tìm ra chúng, Một chiếc bình để mang tất cả và trong bóng tối trói buộc họ.
Marti Nito

Câu trả lời:


342

Nói tóm lại, Uber JAR là một JAR chứa mọi thứ.

Thông thường trong Maven, chúng tôi dựa vào quản lý phụ thuộc. Một tạo phẩm chỉ chứa các lớp / tài nguyên của chính nó. Maven sẽ chịu trách nhiệm tìm hiểu tất cả các tạo tác (JAR, v.v.) mà dự án phụ thuộc vào thời điểm dự án được xây dựng.

Một uber-jar là một cái gì đó có tất cả các phụ thuộc và trích xuất nội dung của các phụ thuộc và đặt chúng với các lớp / tài nguyên của chính dự án, trong một JAR lớn. Bằng cách sử dụng uber-jar như vậy, thật dễ dàng để thực hiện, bởi vì bạn sẽ chỉ cần một JAR lớn thay vì hàng tấn JAR nhỏ để chạy ứng dụng của bạn. Nó cũng dễ dàng phân phối trong một số trường hợp.

Chỉ là một lưu ý phụ. Tránh sử dụng uber-jar làm phụ thuộc Maven, vì nó đang phá hỏng tính năng phân giải phụ thuộc của Maven. Thông thường chúng tôi chỉ tạo uber-jar cho tạo phẩm cuối cùng để triển khai thực tế hoặc phân phối thủ công, nhưng không đưa vào kho lưu trữ Maven.


Cập nhật: Tôi vừa phát hiện ra mình chưa trả lời một phần của câu hỏi: "Điểm đổi tên của các gói phụ thuộc là gì?". Dưới đây là một số cập nhật ngắn gọn và hy vọng sẽ giúp mọi người có câu hỏi tương tự.

Tạo uber-jar để dễ triển khai là một trường hợp sử dụng plugin bóng râm. Ngoài ra còn có các trường hợp sử dụng phổ biến khác liên quan đến đổi tên gói.

Ví dụ: tôi đang phát triển Foothư viện, phụ thuộc vào một phiên bản cụ thể (ví dụ 1.0) của Barthư viện. Giả sử tôi không thể sử dụng phiên bản Barlib khác (vì API thay đổi hoặc các sự cố kỹ thuật khác, v.v.). Nếu tôi chỉ đơn giản tuyên bố Bar:1.0Foosự phụ thuộc của Maven, thì có thể rơi vào một vấn đề: QuxDự án phụ thuộc Foovà cũng có thể Bar:2.0(và nó không thể sử dụng Bar:1.0Quxcần sử dụng tính năng mới trong Bar:2.0). Đây là vấn đề nan giải: nên Quxsử dụng Bar:1.0( Quxmã nào sẽ không hoạt động) hoặc Bar:2.0(màFoo mã nào sẽ không hoạt động)?

Để giải quyết vấn đề này, nhà phát triển Foocó thể chọn sử dụng plugin bóng râm để đổi tên cách sử dụng của nó Bar, để tất cả các lớp trong Bar:1.0jar được nhúng trong Foojar và gói của các Barlớp nhúng được thay đổi từ com.barthành com.foo.bar. Bằng cách làm như vậy, Quxcó thể phụ thuộc một cách an toàn Bar:2.0bởi vì bây giờ Fookhông còn phụ thuộc vào nữa Barvà nó đang sử dụng là bản sao "thay đổi" của chính nó Barnằm trong gói khác.


5
Cảm ơn, điều đó giúp rất nhiều. Có phải nó được gọi là "shading" bởi vì nó che giấu sự phụ thuộc và các lọ khác bên trong uber-jar?
sự không có

6
Tôi không thực sự chắc chắn về lý do đằng sau tên, nhưng từ trang đầu của nó, có vẻ như gợi ý "bóng mờ" đang mô tả sự "che giấu" của sự phụ thuộc. Vì bạn có thể tùy ý bao gồm một số phụ thuộc trong JAR được tô bóng, plugin bóng râm cũng sẽ tạo ra một POM chính xác cho bạn để loại bỏ các phụ thuộc được bao gồm. Có vẻ như shading đang mô tả quá trình này
Adrian Shum

1
@AdrianShum: Bạn có thể đề xuất cách tạo bình uber mà không cần sử dụng plugin bóng râm không? Hay cụ thể là làm thế nào để giải quyết "làm hỏng tính năng phân giải phụ thuộc của Maven"?
Suraj Menon

3
@SurajMenon: Sử dụng plugin Shadow là cách dễ nhất để tạo uber-jar. Tuy nhiên, bạn cũng có thể sử dụng plugin hội và sử dụng bộ jar-with-dependencymô tả tích hợp. Đối với vấn đề phụ thuộc vào việc sử dụng uber-jar, tôi đã đề cập trong câu trả lời của mình: Không sử dụng uber-jar làm phụ thuộc, thời gian. Chi tiết hơn một chút: trước khi bạn tạo uber-jar, bạn nên có một dự án bình thường với sự phụ thuộc bình thường. Cổ vật ban đầu đó là thứ bạn nên sử dụng làm phụ thuộc (thay vì uber-jar)
Adrian Shum

1
Chỉ là một câu hỏi nhỏ: Nó có ngừng hoạt Class.forNameđộng không?
SOFe

64

Gần đây tôi đã tự hỏi tại sao sắc thái tìm kiếm và thay đổi một vài (nhưng không phải tất cả) các phụ thuộc của nó. Đây là lời giải thích từ người bảo trì dự án, @kimchy :

Phần tô bóng là có chủ ý, các thư viện được tô bóng mà chúng tôi sử dụng trong elaticsearch dành cho tất cả mục đích và phần mục đích của elaticsearch, phiên bản được sử dụng gắn chặt với những gì elaticsearch tiếp xúc và cách nó sử dụng thư viện dựa trên nội bộ về cách thư viện hoạt động (và thay đổi giữa các phiên bản), netty và ổi là những ví dụ tuyệt vời.

Btw, tôi không có vấn đề gì với việc thực sự cung cấp một vài lọ thuốc thuật, một cái có lucene không được tô bóng, và một cái có Lucene được tô bóng. Không chắc chắn làm thế nào để làm điều đó với maven mặc dù. Ví dụ, tôi không muốn cung cấp một phiên bản không che giấu netty / jackson, vì sử dụng el elearch sâu sử dụng sâu sắc với họ (ví dụ: sử dụng cải tiến đệm sắp tới với bất kỳ phiên bản netty nào trước đây ngoại trừ phiên bản hiện tại thực sự sử dụng nhiều bộ nhớ hơn so với sử dụng ít hơn đáng kể).

- https://github.com/elaticsearch/elaticsearch/issues/2091#issuecomment-7156766

Và một cái khác ở đây từ drewr :

Việc tạo bóng rất quan trọng để giữ cho các phụ thuộc của chúng tôi (đáng chú ý là nhỏ, lucene, ổi) gần với mã của chúng tôi để chúng tôi có thể khắc phục sự cố ngay cả khi nhà cung cấp ngược dòng tụt lại phía sau. Có thể chúng tôi sẽ phân phối các phiên bản đã được mô đun hóa của mã, điều này sẽ giúp giải quyết vấn đề cụ thể của bạn (ví dụ # 2091), nhưng chúng tôi không thể loại bỏ các phụ thuộc được tô bóng tại thời điểm này. Bạn có thể xây dựng một phiên bản ES cục bộ cho mục đích của mình cho đến khi có giải pháp tốt hơn.

- https://github.com/elaticsearch/elaticsearch/pull/3244#issuecomment-20125452

Vì vậy, đó là một trường hợp sử dụng. Đối với một ví dụ minh họa, dưới đây là cách maven-bóng-plugin được sử dụng trong pom.xml của elSTERearch (v0.90.5). CácartifactSet::include dòng hướng dẫn cho nó những gì phụ thuộc để kéo vào JAR uber (về cơ bản, chúng được giải nén và được đóng gói lại cùng với các lớp riêng của elaticsearch khi sản phẩm jar tìm kiếm mục tiêu được tạo ra (Trong trường hợp bạn chưa biết điều này, thì tệp JAR là chỉ là một tệp ZIP chứa các lớp, tài nguyên của chương trình, v.v. và một số siêu dữ liệu. Bạn có thể trích xuất một tệp để xem cách nó được kết hợp với nhau.)

Các relocations::relocationdòng tương tự nhau, ngoại trừ trong mỗi trường hợp, chúng cũng áp dụng các thay thế được chỉ định cho các lớp của phụ thuộc - trong trường hợp này, đưa chúng vào dưới org.elasticsearch.common.

Cuối cùng, filtersphần này loại trừ một số nội dung khỏi JAR mục tiêu không nên có trong đó - chẳng hạn như siêu dữ liệu JAR, tệp kiến ​​tạo, tệp văn bản, v.v. được đóng gói với một số phụ thuộc, nhưng không thuộc JAR uber.

<plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>2.1</version>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>shade</goal>
                </goals>
            </execution>
        </executions>
        <configuration>
            <minimizeJar>true</minimizeJar>
            <artifactSet>
                <includes>
                    <include>com.google.guava:guava</include>
                    <include>net.sf.trove4j:trove4j</include>
                    <include>org.mvel:mvel2</include>
                    <include>com.fasterxml.jackson.core:jackson-core</include>
                    <include>com.fasterxml.jackson.dataformat:jackson-dataformat-smile</include>
                    <include>com.fasterxml.jackson.dataformat:jackson-dataformat-yaml</include>
                    <include>joda-time:joda-time</include>
                    <include>io.netty:netty</include>
                    <include>com.ning:compress-lzf</include>
                </includes>
            </artifactSet>
            <relocations>
                <relocation>
                    <pattern>com.google.common</pattern>
                    <shadedPattern>org.elasticsearch.common</shadedPattern>
                </relocation>
                <relocation>
                    <pattern>gnu.trove</pattern>
                    <shadedPattern>org.elasticsearch.common.trove</shadedPattern>
                </relocation>
                <relocation>
                    <pattern>jsr166y</pattern>
                    <shadedPattern>org.elasticsearch.common.util.concurrent.jsr166y</shadedPattern>
                </relocation>
                <relocation>
                    <pattern>jsr166e</pattern>
                    <shadedPattern>org.elasticsearch.common.util.concurrent.jsr166e</shadedPattern>
                </relocation>
                <relocation>
                    <pattern>org.mvel2</pattern>
                    <shadedPattern>org.elasticsearch.common.mvel2</shadedPattern>
                </relocation>
                <relocation>
                    <pattern>com.fasterxml.jackson</pattern>
                    <shadedPattern>org.elasticsearch.common.jackson</shadedPattern>
                </relocation>
                <relocation>
                    <pattern>org.joda</pattern>
                    <shadedPattern>org.elasticsearch.common.joda</shadedPattern>
                </relocation>
                <relocation>
                    <pattern>org.jboss.netty</pattern>
                    <shadedPattern>org.elasticsearch.common.netty</shadedPattern>
                </relocation>
                <relocation>
                    <pattern>com.ning.compress</pattern>
                    <shadedPattern>org.elasticsearch.common.compress</shadedPattern>
                </relocation>
            </relocations>
            <filters>
                <filter>
                    <artifact>*:*</artifact>
                    <excludes>
                        <exclude>META-INF/license/**</exclude>
                        <exclude>META-INF/*</exclude>
                        <exclude>META-INF/maven/**</exclude>
                        <exclude>LICENSE</exclude>
                        <exclude>NOTICE</exclude>
                        <exclude>/*.txt</exclude>
                        <exclude>build.properties</exclude>
                    </excludes>
                </filter>
            </filters>
        </configuration>
    </plugin>
</plugins>

2

Cảnh báo nhỏ

Mặc dù đó không phải là mô tả lý do tại sao một người muốn sử dụng plugin maven-bóng râm (vì câu trả lời được chọn mô tả nó khá tốt), tôi muốn lưu ý rằng tôi có vấn đề với nó. Nó đã thay đổi JAR (vì đó là những gì nó đang làm) và nó đã gây ra sự hồi quy trong phần mềm của tôi.

Vì vậy, thay vì sử dụng cái này (hoặc maven-jarjar-plugin), tôi đã sử dụng nhị phân của JarJar dường như hoạt động mà không gặp vấn đề gì.

Tôi đang đăng lên đây giải pháp của mình vì tôi phải mất một thời gian để tìm ra giải pháp hợp lý.


Tệp JAR của Downlaod JarJar

Bạn có thể tải xuống jar từ đây: https://code.google.com.vn/p/jarjar/ Trong menu bên trái, bạn đã có một liên kết để tải xuống.


Cách sử dụng JarJar để di chuyển các lớp của JAR từ gói này sang gói khác

Trong ví dụ này, chúng tôi sẽ thay đổi gói từ "com.fasterxml.jackson" thành "io.kuku.dependencies.com.fasterxml.jackson". - JAR nguồn được gọi là "jackson-databind-2.6.4.jar" và JAR được sửa đổi (đích) mới được gọi là "kuku-jackson-databind-2.6.4.jar". - Tệp JAR "jarjar" có trong phiên bản 1.4

  1. Tạo một tệp "Rules.txt". Nội dung của tệp phải là (xem khoảng thời gian trước ký tự '@'): rule com.fasterxml.jackson. ** io.kuku.dependencies.com.fasterxml.jackson. @ 1

  2. Chạy lệnh sau: java -jar jarjar-1.4.jar process Rules.txt jackson-databind-2.6.4.jar kuku-jackson-databind-2.6.4.jar


Cài đặt các JAR đã sửa đổi vào kho lưu trữ cục bộ

Trong trường hợp này, tôi đang cài đặt 3 tệp nằm trong thư mục "c: \ my-jars \".

mvn install: install-file -Dfile = C: \ my-jars \ kuku-jackson-annotations-2.6.4.jar -DgroupId = io.kuku.dependencies -DartifactId = kuku-jackson-annotations -Dversion = 2.6.4 - Dpackaging = jar

mvn install: install-file -Dfile = C: \ my-jars \ kuku-jackson-core-2.6.4.jar -DgroupId = io.kuku.dependencies -DartifactId = kuku-jackson-core -Dversion = 2.6.4 - Dpackaging = jar

mvn install: install-file -Dfile = C: \ my-jars \ kuku-jackson-databind-2.6.4.jar -DgroupId = io.kuku.dependencies -DartifactId = kuku-jackson-annotations -Dversion = 2.6.4 - Dpackaging = jar


Sử dụng các JAR đã sửa đổi trong pom của dự án

Trong ví dụ này, đây là yếu tố "phụ thuộc" trong dự án pom:

<dependencies>
    <!-- ================================================== -->
    <!-- kuku JARs -->
    <!-- ================================================== -->
    <dependency>
        <groupId>io.kuku.dependencies</groupId>
        <artifactId>kuku-jackson-annotations</artifactId>
        <version>2.6.4</version>
    </dependency>
    <dependency>
        <groupId>io.kuku.dependencies</groupId>
        <artifactId>kuku-jackson-core</artifactId>
        <version>2.6.4</version>
    </dependency>
    <dependency>
        <groupId>io.kuku.dependencies</groupId>
        <artifactId>kuku-jackson-databind</artifactId>
        <version>2.6.4</version>
    </dependency>
</dependencies>

1
Cảm ơn bạn cho đề nghị thay thế này. Đây không phải là điều tôi đang tìm kiếm nhưng hóa ra là một giải pháp đơn giản và nhanh chóng hơn nhiều để áp dụng các bản dịch gói 1 lần trên các thư viện cũ sẽ không bao giờ thay đổi.
Tách

Bạn có tìm ra lý do của những thất bại đó bằng cách so sánh nội dung của đầu ra tương ứng của họ không?
Tribbloid

2

Tôi nghĩ một ví dụ về sự cần thiết của bình "bóng mờ" là chức năng AWS Lambda. Chúng dường như chỉ cho phép bạn tải lên 1 jar chứ không phải toàn bộ bộ sưu tập .jars như bạn tìm thấy trong tệp .war thông thường. Vì vậy, việc tạo một .jar duy nhất với tất cả các phụ thuộc của dự án cho phép bạn làm điều này.

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.