Для чего используется плагин maven-shade-plugin и почему вы хотите переместить пакеты Java?

Я обнаружил, что maven-shade-plugin используется в чьем-то файле pom.xml. Я никогда раньше не использовал maven-shade-plugin (и я Maven n00b), поэтому я попытался понять причину использования этого и то, что он делает.

Я посмотрел на документы Maven, однако не могу понять это утверждение:

"Этот плагин предоставляет возможность упаковать артефакт в uber-jar, включая его зависимости, и затемнить - то есть переименовать - пакеты некоторых зависимостей". Документация на странице не выглядит очень удобной для новичков.

Что такое "Uber Jar"? Почему кто-то хочет сделать один? Какой смысл переименовывать пакеты зависимостей? Я попытался просмотреть примеры на странице apache maven-shade-plugin, такие как "Выбор содержимого для Uber Jar", но до сих пор не могу понять, что происходит с "затенением".

Будем благодарны за любые указатели на иллюстративные примеры / варианты использования (с объяснением того, почему в этом случае требуется затенение - какую проблему он решает). Наконец, когда я должен использовать плагин maven-shade-plugin?

3 ответа

Решение

Короче говоря, Uber JAR - это JAR, содержащий все.

Обычно в Maven мы полагаемся на управление зависимостями. Артефакт содержит только свои классы / ресурсы. Maven будет нести ответственность за обнаружение всех артефактов (JAR и т. Д.), Которые будут выполняться в зависимости от проекта.

Uber-jar - это то, что берет все зависимости, извлекает содержимое зависимостей и помещает их вместе с классами / ресурсами самого проекта в один большой JAR-файл. Имея такой uber-jar, его легко выполнить, потому что для запуска вашего приложения вам понадобится всего один большой JAR вместо множества маленьких JAR. Это также облегчает распространение в некоторых случаях.

Просто примечание. Избегайте использования uber-jar в качестве зависимости Maven, так как это разрушает функцию разрешения зависимостей в Maven. Обычно мы создаем uber-jar только для конечного артефакта для фактического развертывания или для ручного распространения, но не для помещения в репозиторий Maven.


Обновление: я только что обнаружил, что не ответил ни на одну часть вопроса: "Какой смысл переименовывать пакеты зависимостей?". Вот некоторые краткие обновления и, надеюсь, помогут людям, имеющим схожий вопрос.

Создание Uber-JAR для простоты развертывания является одним из вариантов использования плагина Shade. Есть и другие распространенные случаи использования, которые включают переименование пакетов.

Например, я разрабатываю Foo библиотека, которая зависит от конкретной версии (например, 1.0) Bar библиотека. Предполагая, что я не могу использовать другую версию Bar lib (из-за изменения API или других технических проблем и т. д.). Если я просто заявляю Bar:1.0 как Fooзависимость в Maven, можно попасть в проблему: Qux проект зависит от Foo, а также Bar:2.0 (и он не может использовать Bar:1.0 так как Qux необходимо использовать новую функцию в Bar:2.0). Вот дилемма: следует Qux использование Bar:1.0 (который Quxкод не будет работать) или Bar:2.0 (который Fooкод не сработает)?

Чтобы решить эту проблему, разработчик Foo можете использовать плагин Shade, чтобы переименовать его использование Barтак что все классы в Bar:1.0 банка встроена в Foo банка и упаковка Bar классы изменены с com.bar в com.foo.bar, Тем самым, Qux может безопасно зависит от Bar:2.0 потому что сейчас Foo больше не зависит от Barи использует собственную копию "измененного" Bar находится в другой упаковке.

Я недавно задавался вопросом, почему эластичный поиск затеняет и перемещает некоторые (но не все) его зависимости. Вот объяснение от сопровождающего проекта, kimchy:

Затенение является преднамеренным, затененные библиотеки, которые мы используем в эластичном поиске, предназначены для всех целей и целей части эластичного поиска, используемая версия тесно связана с тем, что демонстрирует эластичный поиск, и как она использует библиотеку, основываясь на внутренних принципах работы библиотеки (и что изменения между версиями), нетти и гуава являются отличными примерами.

Кстати, у меня нет проблем с тем, чтобы на самом деле предоставить несколько банок с эластичным поиском, один с люценом, не затененный, а другой с люценом. Не уверен, как это сделать с Mave n, хотя. Я не хочу предоставлять версию, которая не затеняет нетти / джексона, например, из-за глубокого запугивания, которое имеет с ними эластичный поиск (например, использование предстоящего улучшения буферизации с любой предыдущей версией netty, за исключением текущей, будет на самом деле использовать больше памяти по сравнению с использованием значительно меньше).

- https://github.com/elasticsearch/elasticsearch/issues/2091

И еще один здесь от drewr:

Затенение важно, чтобы наши зависимости (в частности, netty, lucene, guava) были близки к нашему коду, чтобы мы могли исправить проблему, даже если вышестоящий провайдер отстает. Возможно, мы будем распространять модульные версии кода, которые помогут решить вашу конкретную проблему (например, #2091), но в настоящее время мы не можем просто удалить затененные зависимости. Вы можете создать локальную версию ES для своих целей, пока не найдете лучшего решения.

- https://github.com/elasticsearch/elasticsearch/pull/3244

Итак, это один из вариантов использования. Что касается иллюстративного примера, то ниже показано, как mave n-shade-plugin используется в файле pse.xml эластичного поиска (v0.90.5). artifactSet::include линии указывают ему, какие зависимости нужно вставить в UAR-JAR-файл (в основном они распаковываются и переупаковываются вместе с собственными классами эластичного поиска, когда создается целевой Jar-архив эластичного поиска. (Если вы этого еще не знали, файл JAR просто ZIP-файл, содержащий классы программы, ресурсы и т. д., а также некоторые метаданные. Вы можете извлечь один из них, чтобы увидеть, как он составлен.)

relocations::relocation линии похожи, за исключением того, что в каждом случае они также применяют указанные замены к классам зависимости - в этом случае, приводя их к org.elasticsearch.common,

Наконец то filters section исключает некоторые вещи из целевого JAR, которых там быть не должно - такие как метаданные JAR, файлы сборки ant, текстовые файлы и т. д., которые упакованы с некоторыми зависимостями, но не принадлежат UAR JAR.

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

Я думаю, что одним из примеров необходимости "затененной" банки является функция AWS Lambda. Кажется, что они позволяют загружать только 1 банку, а не всю коллекцию файлов.jar, как в типичном файле.war. Итак, создание единого файла.jar со всеми зависимостями проекта позволяет вам это сделать.


Небольшое предупреждение

Хотя это не описывает, почему кто-то хотел бы использовать плагин maven-shade-plugin (так как выбранный ответ описывает его довольно хорошо), я хотел бы отметить, что у меня были проблемы с ним. Это изменило JAR (так как это то, что он делает), и это вызвало регресс в моем программном обеспечении.

Таким образом, вместо того, чтобы использовать это (или maven-jarjar-plugin), я использовал бинарный файл JarJar, который, кажется, работает без проблем.

Я публикую здесь свое решение, так как мне потребовалось некоторое время, чтобы найти достойное решение.


Загрузите JAR-файл JarJar

Вы можете скачать банку отсюда: https://code.google.com/p/jarjar/ В левом меню у вас есть ссылка для его загрузки.


Как использовать JarJar для перемещения классов JAR из одного пакета в другой

В этом примере мы изменим пакет с "com.fasterxml.jackson" на "io.kuku.dependencies.com.fasterxml.jackson". - Исходный JAR называется "jackson-databind-2.6.4.jar", а новый модифицированный (целевой) JAR называется "kuku-jackson-databind-2.6.4.jar". - JAR-файл "jarjar" находится в версии 1.4

  1. Создайте файл "rules.txt". Содержимое файла должно быть (смотрите точку перед символом "@"): правило com.fasterxml.jackson.** io.kuku.dependencies.com.fasterxml.jackson.@1

  2. Выполните следующую команду: java -jar jarjar-1.4.jar process rules.txt jackson-databind-2.6.4.jar kuku-jackson-databind-2.6.4.jar


Установка модифицированных JAR-файлов в локальный репозиторий

В этом случае я устанавливаю 3 файла, расположенных в папке "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= баночка

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= баночка

mvn install:install-file -Dfile=C:\my-jars\kuku-jackson-databind-2.6.4.jar -DgroupId=io.kuku.dependencies -DartifactId= Куку-Джексон-аннотации -Dversion=2.6.4 -Dpackaging= баночка


Использование модифицированных файлов JAR в pom проекта

В этом примере это элемент "dependencies" в проектах 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>
Другие вопросы по тегам