Log4J2 动态附加程序不适用于 maven-shade-plugin

问题描述 投票:0回答:3

我以编程方式添加附加程序。它一直有效,直到我添加

maven-shade-plugin
。我想知道是什么让我的附加程序失败。

在这些场景中,appender 是否有效:

  1. ✅ 来自 IDE (IntelliJ IDEA)
  2. ❌ 带遮光罩(Uber/fat)罐<-- now works ✅ see answer
  3. ✅ 使用单独的 jar(应用程序 jar、log4j jar)
  4. ❌ 使用应用程序 jar,并将 log4j jar 解压缩到文件夹中
  5. ✅ 使用应用程序 jar,并重新压缩 log4j 文件夹

示例项目

使用上面的示例项目重现场景

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

相关问题

java maven log4j2
3个回答
2
投票

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
    ,您将失去额外的组件,例如属性源,
  • 将 JAR 标记为多版本 jar:一些用于收集调用者信息的类在 JDK 11 中被替换。因此,某些 Log4j 类有两个版本(JDK 8 和 JDK 9+)。如果您不将 JAR 标记为多版本,它将无法在 JDK 11+ 上运行。

编辑: 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>
这将有效地将小 

spring-boot-loader

 添加到您的应用程序中。该库的 2.x 版本需要 Java 8,而 3.x 版本需要 Java 17。
    


1
投票
经过更多调查,我向示例项目

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 -->
我不喜欢这两种解决方案,因为:

    如果添加文件的副本,则需要更新它,以防更新 Log4j2。您可以使用这个
  • 第 3 方插件,但随后您将依赖第 3 方插件。
  • 如果添加过滤器,则需要修改它们,以防修改依赖项(例如,您可能添加包含此
  • dat
     文件的另一个版本的新依赖项)。

0
投票
如果您想使用 Ant 脚本而不是 Maven 或 Gradle,GitHub 项目

MergeLog4j2Plugins 可以解决问题。

它是一个可在 Ant 构建脚本中使用的工具,用于将注释生成的 Log4j2Plugins.dat 与项目库目录中的 Jars 中找到的多个 Log4j2Plugins.dat 文件合并。

© www.soinside.com 2019 - 2024. All rights reserved.