我的项目中有以下情况:
一个具有自己依赖项的大型模块(称为转换器)正在集成到主应用程序中(由不同的人单独开发,并且有自己的部分重叠依赖项);
最初,这个转换器模块可以作为可执行 jar 从命令行调用,因此它有自己的入口点(定义了 main() 方法的可运行类);这个可执行 jar 总是通过 maven shade 插件创建为 uber-jar;
现在这个转换器模块必须可以从主应用程序中额外调用(为此,我现在在形成命令行参数后直接调用入口点类的 main())。主应用程序也已创建为 uber-jar,并计划继续以这种方式创建。
因此,对于这种情况,我将使用 shade 插件实现正确的依赖分离,为此,我在转换器模块的 pom.xml 中添加了以下重定位规范:
<relocations>
<relocation>
<pattern>com</pattern>
<shadedPattern>quase.com</shadedPattern>
</relocation>
<!-- ... other top-level patterns for converter dependencies -->
<relocation>
<pattern>org</pattern>
<shadedPattern>quase.org</shadedPattern>
<excludes>
<exclude>org.aau.**</exclude> <!-- my own code for converter is not shaded -->
</excludes>
</relocation>
</relocations>
结果,转换器模块的所有依赖项在组合到主应用程序的 uber-jar 时都被遮蔽(在它们前面加上 quase.)。
此配置的问题是应用程序和转换器都使用日志记录(slf4j 和 log4j),并且从应用程序代码调用转换器方法并开始使用日志记录后,出现以下错误:
log4j:ERROR A "org.apache.log4j.FileAppender" object is not assignable to a "quase.org.apache.log4j.Appender" variable.
log4j:ERROR The class "quase.org.apache.log4j.Appender" was loaded by
log4j:ERROR [sun.misc.Launcher$AppClassLoader@55f96302] whereas object of type
log4j:ERROR "org.apache.log4j.FileAppender" was loaded by [sun.misc.Launcher$AppClassLoader@55f96302].
log4j:ERROR Could not instantiate appender named "file1".
log4j:ERROR A "org.apache.log4j.FileAppender" object is not assignable to a "quase.org.apache.log4j.Appender" variable.
log4j:ERROR The class "quase.org.apache.log4j.Appender" was loaded by
log4j:ERROR [sun.misc.Launcher$AppClassLoader@55f96302] whereas object of type
log4j:ERROR "org.apache.log4j.FileAppender" was loaded by [sun.misc.Launcher$AppClassLoader@55f96302].
log4j:ERROR Could not instantiate appender named "file2".
log4j:ERROR A "org.apache.log4j.ConsoleAppender" object is not assignable to a "quase.org.apache.log4j.Appender" variable.
log4j:ERROR The class "quase.org.apache.log4j.Appender" was loaded by
log4j:ERROR [sun.misc.Launcher$AppClassLoader@55f96302] whereas object of type
log4j:ERROR "org.apache.log4j.ConsoleAppender" was loaded by [sun.misc.Launcher$AppClassLoader@55f96302].
log4j:ERROR Could not instantiate appender named "console".
log4j:WARN No appenders could be found for logger (org.aau.quase.quontology.builder.QuLogHandler).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
所以在我看来,从转换器模块调用的阴影日志代码获取了对已在主应用程序中初始化的非阴影日志代码的引用,并且失败,因为它需要阴影代码(请参阅将非阴影分配给 shaded 的org.apache.log4j.FileAppender
失败quase.org.apache.log4j.Appender
) .
我试图从转换器的 pom.xml 中的阴影中排除日志记录依赖项:
<excludes>
<exclude>org.aau.**</exclude>
<exclude>org.apache.log4j.**</exclude>
<exclude>org.slf4j.**</exclude>
</excludes>
但这导致了进一步的问题:整个应用程序失败如下:
Exception in thread "main" java.lang.NoClassDefFoundError
at org.apache.log4j.Category.class$(Category.java:118)
at org.apache.log4j.Category.<clinit>(Category.java:118)
at org.apache.log4j.LogManager.<clinit>(LogManager.java:82)
at org.slf4j.impl.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:66)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:277)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:288)
at org.aau.quase.application.LoggingProtocolHandler.<clinit>(LoggingProtocolHandler.java:16)
at org.aau.quase.application.QuASEApplication$1.<init>(QuASEApplication.java:71)
at org.aau.quase.application.QuASEApplication.<init>(QuASEApplication.java:65)
at org.aau.quase.application.util.QuASERunner.main(QuASERunner.java:8)
Caused by: java.lang.ClassNotFoundException: quase/org.apache.log4j.Category
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
... 10 more
看起来转换器代码仍然以某种方式期望阴影版本,因为它无法找到quase/org.apache.log4j.Category
并且 quase 是阴影前缀。
我究竟做错了什么?任何帮助是极大的赞赏。