新项目是否应使用logback而不是log4j作为日志记录框架?
或者换句话说:'logback是否比log4j好(留下SLF4J -'feature'的logback旁边)?'
我是Java的新手,刚刚开始弄清楚类加载器的概念.现在我对log4j有一些关于它使用线程上下文类加载器的问题.
我收到以下错误: A "org.apache.log4j.ConsoleAppender" object is not assignable to a "org.apache.log4j.Appender" variable. The class "org.apache.log4j.Appender" was loaded by [java.net.URLClassLoader@105691e] whereas object of type "org.apache.log4j.ConsoleAppender" was loaded by [sun.misc.Launcher$AppClassLoader@16930e2]. Could not instantiate appender named "CONSOLE".
我的应用程序大致以这种方式工作:在初始化URLClassLoader#1构造并加载一些类,这些类使用log4j.后来构建了URLClassLoader#2(它的URLClassLoader#1是它的父级)并加载了更多的类,这些类也使用了log4j.当URLClassLoader#2用于加载这些类时,会出现上述错误消息(还有一些问题存在同一问题).
我当前的解决方法是在加载有问题的类之前将当前线程上下文类加载器设置为URLClassLoader#2,然后将其重置为旧类:
ClassLoader urlClassLoader; // this is URLClassLoader #2
Thread thread = Thread.currentThread();
ClassLoader loader = thread.getContextClassLoader();
thread.setContextClassLoader(urlClassLoader);
try {
urlClassLoader.loadClass(...)
} finally {
thread.setContextClassLoader(loader);
}
Run Code Online (Sandbox Code Playgroud)
虽然这有效,但我不确定它是否是正确的方法.
任何有关此事的见解将不胜感激.另外,为什么log4j迫使我搞乱线程上下文类加载器?为什么不让我传入类加载器(当我不使用时使用默认的加载器)而不是使用线程的?
我们有很多类代码,它们有一些如下所示的样板:
private static Logger logger = null;
private static Logger getLogger() {
if (logger == null) {
logger = Logger.getLogger(MyClass.class);
}
return logger;
}
Run Code Online (Sandbox Code Playgroud)
这个想法是类可以将调试内容记录到Logger中.需要记录某些东西的第一个代码调用getLogger()并使记录器存在.
关于这种模式,有几件我不喜欢的事情.首先,单例getLogger()不同步并同步它,而正确会无缘无故地给每个后续调用带来负担.
我真的希望能够将它简化为这样:
private static final Logger logger = Logger.getLogger(MyClass.class);
Run Code Online (Sandbox Code Playgroud)
然后我可以直接引用记录器,甚至不用单独的getter.
我担心的问题是,通过这样做,即使从未调用过记录器,我也会在加载类时创建一个Logger.我有10,000多个奇怪的类都调用了getLogger(),所以我实际上在这里创建了多少个Logger实例?如果我的log4j属性包含一些appender,我只是一遍又一遍地引用相同的记录器,或者我是在创建10,000个这样的东西?
我最近在其中一个项目上遇到了一些混乱,Log4j,Slf4j和Commons-Logging的"混合"由于混合了来自不同开源项目的不同JAR.
我看到越来越多的OS项目慢慢转向Slf4j.Logback似乎是Log4j的继承者.我认为它实际上是一个岔路口,但由于没有进一步的发展预期为1.3的Log4j Log4j的和2.0是一个实验性的发展,不知道它是否会永远离开那个状态...我不知道!
Log4j死了吗?