Encontrei o maven-shade-plugin sendo usado no pom.xml de alguém. Eu nunca usei o maven-shade-plugin antes (e sou um Maven n00b), então tentei entender o motivo de usá-lo e o que ele faz.
Eu olhei para os documentos do Maven , mas não consigo entender esta afirmação:
"Este plugin fornece a capacidade de empacotar o artefato em um uber-jar, incluindo suas dependências e sombrear - ou seja, renomear - os pacotes de algumas das dependências."
A documentação da página não parece muito amigável para iniciantes.
O que é um "uber jar?" Por que alguém iria querer fazer um? Qual o sentido de renomear os pacotes das dependências? Tentei seguir os exemplos na página apache do maven-shade-plugin, como "Selecionando conteúdo para o Uber Jar", mas ainda não consigo entender o que está sendo realizado com "sombreamento".
Qualquer indicação de exemplos / casos de uso ilustrativos (com uma explicação de por que o sombreamento foi necessário nesse caso - que problema está resolvendo) seria apreciada. Por fim, quando devo usar o maven-shade-plugin?
fonte
s/reallocation/relocation/
no comentário acima.Respostas:
Uber JAR, em suma, é um JAR que contém tudo.
Normalmente, no Maven, contamos com o gerenciamento de dependências. Um artefato contém apenas as classes / recursos de si mesmo. Maven será responsável por descobrir todos os artefatos (JARs etc.) que o projeto depende de quando o projeto for construído.
Um uber-jar é algo que pega todas as dependências e extrai o conteúdo das dependências e as coloca com as classes / recursos do próprio projeto, em um grande JAR. Por ter esse uber-jar, é fácil para a execução, porque você precisará de apenas um JAR grande em vez de toneladas de JARs pequenos para executar seu aplicativo. Também facilita a distribuição em alguns casos.
Apenas uma nota lateral. Evite usar o uber-jar como dependência do Maven, pois isso está arruinando o recurso de resolução de dependência do Maven. Normalmente, criamos o uber-jar apenas para o artefato final para implantação real ou para distribuição manual, mas não para colocação no repositório Maven.
Atualização: Acabei de descobrir que não respondi a uma parte da pergunta: "Qual é o sentido de renomear os pacotes das dependências?". Aqui estão algumas breves atualizações e, esperançosamente, ajudarão as pessoas com perguntas semelhantes.
Criar o uber-jar para facilitar a implantação é um caso de uso do plugin de sombra. Há também outros casos de uso comuns que envolvem renomeação de pacotes.
Por exemplo, estou desenvolvendo uma
Foo
biblioteca, que depende de uma versão específica (por exemplo, 1.0) daBar
biblioteca. Supondo que eu não possa fazer uso de outra versão daBar
lib (porque alterações na API ou outros problemas técnicos, etc.). Se eu simplesmente declararBar:1.0
comoFoo
dependência do Maven, é possível cair em um problema: UmQux
projeto dependeFoo
e tambémBar:2.0
(e não pode ser usadoBar:1.0
porqueQux
precisa usar o novo recursoBar:2.0
). Aqui está o dilema: deveQux
usarBar:1.0
(cujoQux
código não funcionará) ouBar:2.0
(queFoo
código não funcionará)?Para resolver esse problema, o desenvolvedor de
Foo
pode optar por usar o plugin de sombra para renomear o uso deBar
, para que todas as classes noBar:1.0
jar sejam incorporadas noFoo
jar e o pacote dasBar
classes incorporadas seja alterado decom.bar
paracom.foo.bar
. Ao fazer isso,Qux
pode com segurança depender,Bar:2.0
porque agoraFoo
não depende maisBar
e está usando sua própria cópia de "alterado",Bar
localizada em outro pacote.fonte
jar-with-dependency
descritor interno. Para problemas de exclusão de dependência usando o uber-jar, já mencionei na minha resposta: Não use o uber-jar como dependência, ponto final. Um pouco mais detalhadamente: antes de criar o uber-jar, você deve ter um projeto normal com dependência normal. Esse artefato original é o que você deve usar como dependência (em vez do uber-jar)Class.forName
de funcionar?Recentemente, fiquei me perguntando por que a pesquisa elástica obscurece e realoca algumas (mas não todas) de suas dependências. Aqui está uma explicação do mantenedor do projeto, @kimchy :
- https://github.com/elasticsearch/elasticsearch/issues/2091#issuecomment-7156766
E outro aqui de drewr :
- https://github.com/elasticsearch/elasticsearch/pull/3244#issuecomment-20125452
Então, esse é um caso de uso. Como exemplo ilustrativo, abaixo está como o maven-shade-plugin é usado no pom.xml da elasticsearch (v0.90.5). o
artifactSet::include
linhas o instruem sobre quais dependências extrair no JAR uber (basicamente, são descompactadas e empacotadas juntamente com as próprias classes do elasticsearch quando o jar de elasticsearch de destino é produzido. (Caso você ainda não saiba disso, um arquivo JAR é apenas um arquivo ZIP que contém as classes, recursos, etc. do programa e alguns metadados. Você pode extrair um para ver como ele é montado.)As
relocations::relocation
linhas são semelhantes, exceto que, em cada caso, elas também aplicam as substituições especificadas às classes de dependência - nesse caso, trazendo-as para baixoorg.elasticsearch.common
.Finalmente, a
filters
seção exclui algumas coisas do JAR de destino que não deveriam estar lá - como metadados JAR, arquivos de construção de formigas, arquivos de texto etc. que são empacotados com algumas dependências, mas que não pertencem a um JAR superior.fonte
Pequeno aviso
Embora isso não descreva por que alguém gostaria de usar o plugin maven-shade-plugin (como a resposta selecionada o descreve muito bem), gostaria de observar que tive problemas com ele. Ele mudou o JAR (desde que o que está fazendo) e causou regressão no meu software.
Então, em vez de usar este (ou o maven-jarjar-plugin), usei o binário do JarJar, que parece funcionar sem problemas.
Estou postando aqui minha solução, pois demorei algum tempo para encontrar uma solução decente.
Baixar o arquivo JAR do JarJar
Você pode fazer o download do jar aqui: https://code.google.com/p/jarjar/ No menu à esquerda, você tem um link para fazer o download.
Como usar o JarJar para realocar classes de um JAR de um pacote para outro
Neste exemplo, mudaremos o pacote de "com.fasterxml.jackson" para "io.kuku.dependencies.com.fasterxml.jackson". - O JAR de origem é chamado "jackson-databind-2.6.4.jar" e o novo JAR modificado (de destino) é chamado "kuku-jackson-databind-2.6.4.jar". - O arquivo JAR "jarjar" está na versão 1.4
Crie um arquivo "rules.txt". O conteúdo do arquivo deve ser (observe o período antes do caractere '@'): regra com.fasterxml.jackson. ** io.kuku.dependencies.com.fasterxml.jackson. @ 1
Execute o seguinte comando: java -jar jarjar-1.4.jar process rules.txt jackson-databind-2.6.4.jar kuku-jackson-databind-2.6.4.jar
Instalando os JARs modificados no repositório local
Nesse caso, estou instalando 3 arquivos localizados na pasta "c: \ my-jars \".
mvn install: install-file -Dfile = C: \ meus-jarros \ kuku-jackson-anotações-2.6.4.jar -DgroupId = io.kuku.dependencies -DartifactId = kuku-jackson-anotações -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: \ meus-jars \ kuku-jackson-databind-2.6.4.jar -DgroupId = io.kuku.dependencies -DartifactId = kuku-jackson-anotações -Dversion = 2.6.4 - Dpackaging = jar
Usando os JARs modificados no pom do projeto
Neste exemplo, este é o elemento "dependencies" nos projetos pom:
fonte
Acho que um exemplo da necessidade de um jar "sombreado" é uma função do AWS Lambda. Eles parecem permitir apenas o upload de 1 jar, não uma coleção inteira de .jars como você encontraria em um arquivo .war típico. Portanto, criar um único .jar com todas as dependências do projeto permite fazer isso.
fonte