我以编程方式添加附加程序。它一直有效,直到我添加
maven-shade-plugin
。我想知道是什么让我的附加程序失败。
在这些场景中,appender 是否有效:
mvn clean compile
mkdir -p local/log4j-jars
unzip $HOME/.m2/repository/org/apache/logging/log4j/log4j-api/2.17.2/log4j-api-2.17.2.jar -d local/log4j-jars
unzip -o $HOME/.m2/repository/org/apache/logging/log4j/log4j-core/2.17.2/log4j-core-2.17.2.jar -d local/log4j-jars
cd local/log4j-jars
zip -r ../log4j-jars.zip .
cd ../..
# Scenario 2 ❌ uses fat jar
java -cp "target/log4j-test-1.0-SNAPSHOT.jar" org.example.Main
# Scenario 3 ✅ uses separate jars
java -cp "target/original-log4j-test-1.0-SNAPSHOT.jar:$HOME/.m2/repository/org/apache/logging/log4j/log4j-core/2.17.2/log4j-core-2.17.2.jar:$HOME/.m2/repository/org/apache/logging/log4j/log4j-api/2.17.2/log4j-api-2.17.2.jar" org.example.Main
# Scenario 4 ❌ uses log4j files unzipped
java -cp "target/original-log4j-test-1.0-SNAPSHOT.jar:local/log4j-jars" org.example.Main
# Scenario 5 ✅ uses log4j files re-zipped
java -cp "target/original-log4j-test-1.0-SNAPSHOT.jar:local/log4j-jars.zip" org.example.Main
在场景 5 中,我注意到我可以删除
META-INF
中的一些文件,但为了让我的附加程序正常工作,我需要保留以下内容:
META-INF
org
(包含Log4j2Plugins.dat
)services
(没有这个,应用程序甚至会崩溃)versions
MANIFES.MF
Log4j2Plugins.dat
的问题,但在我的项目中只有一个文件,在 log4j2-core
中。META-INF
文件夹没有像 jar 中那样进行处理)maven-shade-plugin
的问题在于它破坏了原始 jar 的清单并覆盖了重要资源。我发现 spring-boot-maven-plugin
更有用,它也可以被根本不使用 Spring 的应用程序使用。
Log4j 上下文中的
maven-shade-plugin
需要最小配置,如本问题中的 :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-transform-maven-shade-plugin-extensions</artifactId>
<version>0.1.0</version>
</dependency>
</dependencies>
<configuration>
<transformers>
<transformer implementation="org.apache.logging.log4j.maven.plugins.shade.transformer.Log4j2PluginCacheFileTransformer"/>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Multi-Release>true</Multi-Release>
</manifestEntries>
</transformer>
</transformers>
</configuration>
</plugin>
此配置负责:
Log4j2Plugins.dat
文件。如果没有
Log4j2PluginCacheFileTransformer
,您将无法使用除
log4j-api
和
log4j-core
、之外的其他组件库
ServiceResourceTransformer
,您将失去额外的组件,例如属性源,
编辑: maven-shade-plugin
的所有这些问题归结为一个:每次两个罐子有一个同名的文件时,它必须以某种方式合并。这就是为什么我更喜欢
spring-boot-maven-plugin
:它不是破坏多个 jar 并将其文件添加到单个存档中,而是将原始 jar 添加到存档中。生成的 jar 的确切结构在可执行 Jar 格式中描述。 用法很简单:只需将
repackage
目标添加到您的构建中并删除
maven-shade-plugin
。
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.10</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
这将有效地将小 添加到您的应用程序中。该库的 2.x 版本需要 Java 8,而 3.x 版本需要 Java 17。
log4j2-thread-context添加了一个新的提交并进行了修复,所以现在它工作正常。
我还添加了与Log4j2Plugins.dat
相关的另一个修复(请参阅运行 fatjar 时无法加载 log4j2 ),我在问题中没有提及。 总结:
Multi-Release
将所需的
MANIFEST.MF
条目添加到
ManifestResourceTransformer
。
Log4j2Plugins.dat
复制正确的
IncludeResourceTransformer
。
Multi-Release
条目。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.4.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<filters>
<!-- Ignore these files, we will write the right one below -->
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>**/Log4j2Plugins.dat</exclude>
</excludes>
</filter>
</filters>
<transformers>
<!--
Copies the right Log4j2Plugins.dat file.
You need a copy of the right Log4j2Plugins.dat file from log4j2-core into src/main/resources.
You can get that file with these commands:
log4j2_version=2.17.2
rm src/main/resources/Log4j2Plugins-*.dat
unzip -j $HOME/.m2/repository/org/apache/logging/log4j/log4j-core/${log4j2_version}/log4j-core-${log4j2_version}.jar META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat -d src/main/resources
mv src/main/resources/Log4j2Plugins.dat src/main/resources/Log4j2Plugins-${log4j2_version}.dat
-->
<transformer implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer">
<resource>META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat</resource>
<file>src/main/resources/Log4j2Plugins-${log4j2.version}.dat</file>
</transformer>
<!-- Adds the Multi-Release entry in MANIFEST.MF -->
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.example.Main</mainClass>
<manifestEntries>
<Multi-Release>true</Multi-Release>
</manifestEntries>
</transformer>
</transformers>
</configuration>
</plugin>
关于Log4j2Plugins.dat
,
IncludeResourceTransformer
的另一种选择是过滤除
log4j-core
中版本之外的所有版本。例如:
<filter>
<artifact>io.github.technologize:*</artifact>
<excludes>
<exclude>**/Log4j2Plugins.dat</exclude>
</excludes>
</filter>
<!-- filter other artifacts if needed -->
我不喜欢这两种解决方案,因为:
dat
文件的另一个版本的新依赖项)。
MergeLog4j2Plugins 可以解决问题。
它是一个可在 Ant 构建脚本中使用的工具,用于将注释生成的 Log4j2Plugins.dat 与项目库目录中的 Jars 中找到的多个 Log4j2Plugins.dat 文件合并。