在 Java 中如何实现像 tomcat 中的那样,多个 web 项目都可以有自己的日志输出。我模拟了一下,大致的过程是:主 main 函数中配置一个日志实例(log4j ),然后启动多个线程,每个线程中重新生成一个 ClassLoader ,然后扫描一个目录下的所有 jar 包和配置文件,然后反射执行其中的某个方法(这个方法会打印日志 logger.info("blabla..."))。
但是实验的结果总是,所有的日志都写到了 main 函数中配置的日志实例。我刚开始以为是线程的 contextClassLoader 没有设置,后来在线程中 Thread.currentThread().setContextClassLoader(cl);发现还是不行,被这个问题卡住好久了,网上资料也是各种看,一直没有实现。蓝瘦,香菇。。。
如果您了解的话,一定给我留言,提一下建议和思路也是好的,感谢!
1
Weixiao0725 OP 关于 tomcat 的实现,我也研究了几天, tomcat 的做法是自己实现了一个 ClassLoaderLogManager ,然后启动的时候设置了这个系统属性-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager ,意思好像是通过这个全局统一的日志管理类来根据不同的 ClassLoader 管理日志实例。但是我修改了这部分源代码重新打包到 tomcat 目录下替换了原来的实现类(${tomcat}/bin/tomcat-juli.jar),发现其实当一个 web 项目中比如引入了 log4j 后,其日志的生成并没有与 ClassLoaderLogManager 发生任何关系。而且我发现 log4j 本身也有自己的 LogManager 实现。所以不清楚 tomcat 是如何把各个日志实例区分开的。
|
2
SoloCompany 2016-10-24 00:49:08 +08:00
这问题很简单,和 tomcat 自己的 logger 实现 (juli) 无关
你把 log4j 的实现放到 tomcat/lib 目录的话,一样有同样的问题 同样的,如果你想自己实现容器,首先要保证你的实例互相是隔离的(没有直接的互相引用关系),然后必须确保每个实例所引用到的 log4j 是不同的(就是必须是应用自己的 classloader 加载的实现,而不是 delegate 给 parent 所加载的实现) |
3
Weixiao0725 OP 我以为的隔离只是用不同的 classloader 实例加载相关的 jar ,我也确实是这么做的。但是我不知道为什么似乎我开启了两个线程实验的时候(两个线程中先是生成自己的定制的 classloader ,然后将相关的文件和 jar 包扫描进来,然后调用其中某个类的实例的方法,这个方法会打印一条日志),但是不同 classloader 加载的相关实现都将日志输出到同一个文件中了。
|