我有一个严重的问题,TomcatLoadTimerWeaver
我Log4j
不知道如何解决它。
我正在使用以下内容:
- 雄猫 8
- Spring 框架 4.1.2
- 日志4j 2.1
- SLF4J 1.7.7
- EclipseLink 2.5.2
所有日志都被路由到 SLF4J,我使用 Log4j 2.1 作为日志后端。web.xml
Log4j 被配置为从通过log4jConfiguration
context-param指定的非标准位置获取其配置文件。在Log4jServletContainerInitializer
webapp 启动时正确配置 Log4j。一旦 Spring 配置了TomcatLoadTimeWeaver
.
我想使用 EclipseLink 的加载时间编织,所以我将它添加到我的应用程序上下文中:
<context:load-time-weaver/>
问题是这样的:一旦 SpringTomcatLoadTimeWeaver
通过向 Tomcat's 添加转换器来注册 a WebappClassLoader
,随后第一次尝试通过 SLF4J 记录某些内容会导致 Log4j 被隐式重新初始化:因为我的配置文件不在标准位置(=类路径)我得到错误:
找不到 log4j2 配置文件
从那一刻起,所有日志调用都不再正确处理(= 以我在 MY 中指定的方式log4j.xml
),并且我为 Commons Logging 和 JUL 精心配置的 SLF4J+Log4j+bridges 完全被破坏了。
似乎添加类加载器转换器正在重置 Log4j 中的某些内容,因此它需要重新配置自身:我花了几个小时试图更好地理解这个问题,但如果没有对 Log4j 的深入了解,这并不容易内部结构。
将我log4j.xml
移到log4j2.xml
类路径根目录不是我可以轻易做到的事情(出于部署原因),并且无论如何我都不确定不受我控制的 Log4j 的隐式重新配置是否会是一件好事。
也许加载时间编织器的早期配置(在 Log4j 第一次配置自身之前)会成功,但我不确定如何做到这一点,因为 Log4j 通常应该在 Spring 本身之前设置。
任何建议表示赞赏。
更多详细信息
实际上,问题不会在Spring DefaultContextLoadTimeWeaver
(带有由 EclipseLink(由 触发)实际创建的本机。因此,我的解决方法是注册一个拦截 的初始化并强制再次运行,从而使用我的 webapp 设置重新配置 Log4j。不过,我最终得到了一个可怕的 hack,因为那些 Log4j 类充满了默认和受保护的方法,我不得不使用反射并将我的 bean 后处理器放在包中以使其工作。TomcatLoadTimeWeaver
LocalContainerEntityManagerFactoryBean
EntityManagerFactory
org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet()
org.springframework.context.weaving.DefaultContextLoadTimeWeaver.addTransformer(ClassFileTransformer)
EntityManagerFactory
org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory()
BeanPostProcessor
LocalContainerEntityManagerFactoryBean
org.apache.logging.log4j.web.Log4jWebInitializerImpl.start()
org.apache.logging.log4j.core
欢迎提出更智能的解决方案/建议/替代方法。
实际原因
我进一步调试了整个系统并找出了这个问题的原因。我为此打开了 LOG4J2-903。简而言之,Log4j 使用类加载器toString()
值在映射中搜索当前日志上下文。由于 Tomcat 的WebappClassLoader.toString()
方法在您注册转换器时发生更改,因此 Log4j 无法检索先前配置的上下文并在 EclipseLink+Spring 注册加载时间编织器转换器后立即创建一个新的上下文... :-(