Construindo uma jarra gorda usando maven

118

Tenho uma base de código que desejo distribuir como jar. Ele também depende de jars externos, que desejo agrupar no jar final.

Ouvi dizer que isso pode ser feito usando maven-assembly-plug-in, mas não entendo como. Alguém poderia me apontar alguns exemplos.

No momento, estou usando o frasco de gordura para empacotar o frasco final. Eu quero conseguir a mesma coisa usando o maven.

Bianca
fonte

Respostas:

143

Nota: Se você for um aplicativo de inicialização rápida, leia o final da resposta

Adicione o seguinte plugin ao seu pom.xml A versão mais recente pode ser encontrada em

...
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>CHOOSE LATEST VERSION HERE</version>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
            <executions>
                <execution>
                    <id>assemble-all</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
...

Depois de configurar este plug-in, a execução mvn packageproduzirá dois jars: um contendo apenas as classes do projeto e um segundo jar fat com todas as dependências com o sufixo "-jar-with-dependencies".

se quiser uma classpathconfiguração correta em tempo de execução, adicione também o seguinte plugin

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
                <mainClass>fully.qualified.MainClass</mainClass>
            </manifest>
        </archive>
    </configuration>
</plugin>

Para o aplicativo Spring Boot, use apenas o plugin seguinte (escolha a versão apropriada dele)

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <fork>true</fork>
        <mainClass>${start-class}</mainClass>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>repackage</goal>
            </goals>
        </execution>
    </executions>
</plugin>
Jigar Joshi
fonte
1
A versão atual deste plugin é agora 2.4
guerda
13
Este agora está obsoleto e o plugin maven-shadow deve ser usado em seu lugar. Consulte @phlogratos answer: stackoverflow.com/a/16222965/274350 .
Richard Neish
2
O plugin de montagem do maven pode minimizar o tamanho do frasco de gordura?
Maio 12
1
@Richard Onde você vê que ele está obsoleto? Eu não consegui encontrar nada por aqui maven.apache.org/plugins/maven-assembly-plugin
user3833308
3
@ user3833308 "obsoleto" pode ser a palavra errada, mas a documentação em maven.apache.org/plugins/maven-assembly-plugin diz "Se seu projeto deseja empacotar seu artefato em um uber-jar, o plugin de montagem fornece apenas o básico para obter mais controle, use o plugin Maven Shade. "
Richard Neish,
55

Você pode usar o plugin maven-shadow .

Depois de configurar o plugin de sombra em sua construção, o comando mvn packagecriará um único jar com todas as dependências mescladas nele.

flogratos
fonte
9
Esta agora é a maneira correta de fazer isso. A documentação do maven-assembly-plugin afirma: "Se seu projeto deseja empacotar seu artefato em um uber-jar, o plugin de montagem fornece apenas suporte básico. Para obter mais controle, use o plug-in Maven Shade."
Richard Neish,
Mas como faço para pegar esse único .jar e usá-lo para publicação?
DanGordon
42

Talvez você queira maven-shade-plugin agrupar dependências, minimizar códigos não utilizados e ocultar dependências externas para evitar conflitos.

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.1.1</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <minimizeJar>true</minimizeJar>
                        <createDependencyReducedPom>true</createDependencyReducedPom>
                        <dependencyReducedPomLocation>
                            ${java.io.tmpdir}/dependency-reduced-pom.xml
                        </dependencyReducedPomLocation>
                        <relocations>
                            <relocation>
                                <pattern>com.acme.coyote</pattern>
                                <shadedPattern>hidden.coyote</shadedPattern>
                            </relocation>
                        </relocations>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Referências:

ggrandes
fonte
Se um encontrar Provider org.apache.xerces.jaxp.SAXParserFactoryImpl not found, apenas remova <minimizeJar>true</minimizeJar>.
koppor
Se você receber uma exceção "java.lang.SecurityException: compilação de arquivo de assinatura inválida para atributos principais do manifesto", essa adição à seção de configuração acima ajudará: stackoverflow.com/a/6743609/38368
Danny Varod
12

na verdade, adicionando o

<archive>
   <manifest>
    <addClasspath>true</addClasspath>
    <packageName>com.some.pkg</packageName>                     
    <mainClass>com.MainClass</mainClass>
  </manifest>
</archive>

declaração para maven-jar-plugin não adiciona a entrada de classe principal ao arquivo de manifesto para mim. Tive que adicioná-lo ao maven-assembly-plugin para obtê-lo no manifesto

ameet chaubal
fonte
5

Você pode usar o plugin onejar-maven para empacotamento. Basicamente, ele monta seu projeto e suas dependências em um jar, incluindo não apenas o arquivo jar do projeto, mas também todas as dependências externas como um "jar de jars", por exemplo

<build>
    <plugins>
        <plugin>
            <groupId>com.jolira</groupId>
            <artifactId>onejar-maven-plugin</artifactId>
                <version>1.4.4</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>one-jar</goal>
                        </goals>
                    </execution>
                </executions>
        </plugin>
    </plugins>
</build>

Nota 1: as opções de configuração estão disponíveis na página inicial do projeto .

Nota 2: Por um motivo ou outro, o projeto onejar-maven-plugin não foi publicado no Maven Central. No entanto, jolira.com rastreia o projeto original e o publica com o groupId com.jolira.

Matsev
fonte
É possível escolher as dependências com as quais deseja empacotar? Por exemplo, se a.jar e b.jar forem jars externos e eu quiser empacotar apenas a.jar no jar final, é algo possível / configurável?
bianca
Também vejo coisas de um frasco empacotadas no frasco final também. Isso aumentou muito o tamanho do frasco final. É possível escolher potes externos que você pretende incluir no frasco final? Aqui estão os logs de um jar: pastebin.com/UwniQJ2X
bianca
Não sei se você pode configurar o que está incluso ou não. Basicamente, um jar inclui todas as dependências especificadas por seu projeto, incluindo dependências transitivas, portanto, sim, o jar final provavelmente se tornará grande se você tiver muitas dependências. Algum overhead será adicionado por um jar, a fim de fazer o Java funcionar com a estrutura "jar of jars".
matsev
2

Uma alternativa é usar o plugin de sombra maven para construir um uber-jar.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version> Your Version Here </version>
    <configuration>
            <!-- put your configurations here -->
    </configuration>
    <executions>
            <execution>
                    <phase>package</phase>
                    <goals>
                            <goal>shade</goal>
                    </goals>
            </execution>
    </executions>
</plugin>
Stanislav
fonte