JDK日志框架源码分析
Posted LackMemory
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDK日志框架源码分析相关的知识,希望对你有一定的参考价值。
分析源码先从它是如何被使用或调用开始,如在上篇文章中说的,代码中使用JDK自带的日志是这样开始的:
Logger logger = Logger.getLogger("W");
那么我们看看getLogger方法的内部:
public static Logger getLogger(String name)
LogManager manager = LogManager.getLogManager();
return manager.demandLogger(name);
原来最终是通过LogManager的一个实例获取的,且通过静态方法getLoggrManager获取的这个实例:
public static LogManager getLogManager()
if (manager != null)
manager.readPrimordialConfiguration();
return manager;
这个方法返回的是成员变量manager,那么它在哪里初始化呢?定义处并没有:
// The global LogManager object
private static LogManager manager;
那看来只能在别的地方了。由于并没有创建LogManager的对象,所以不会在构造方法中;由于静态方法的调用会引起类的加载,所以类代码中应该存在一个static块用来初始化manager,一看果然如此:
static
AccessController.doPrivileged(new PrivilegedAction<Object>()
public Object run()
String cname = null;
try
cname = System.getProperty("java.util.logging.manager");
if (cname != null)
try
Class clz = ClassLoader.getSystemClassLoader().loadClass(cname);
manager = (LogManager) clz.newInstance();
catch (ClassNotFoundException ex)
Class clz = Thread.currentThread().getContextClassLoader().loadClass(cname);
manager = (LogManager) clz.newInstance();
catch (Exception ex)
System.err.println("Could not load Logmanager \\"" + cname + "\\"");
ex.printStackTrace();
if (manager == null)
manager = new LogManager();
// Create and retain Logger for the root of the namespace.
manager.rootLogger = manager.new RootLogger();
manager.addLogger(manager.rootLogger);
// Adding the global Logger. Doing so in the Logger.<clinit>
// would deadlock with the LogManager.<clinit>.
Logger.global.setLogManager(manager);
manager.addLogger(Logger.global);
// We don't call readConfiguration() here, as we may be running
// very early in the JVM startup sequence. Instead readConfiguration
// will be called lazily in getLogManager().
return null;
);
第一步是加载系统属性java.util.logging.manager指定的类,该属性在启动java程序时指定,比如使用命令行就在java命令后面用这种形式:
-java.util.logging.manager=xx
从代码可以看出,只有在该系统属性指定的类没有加载成功时才会使用JDK本身的LogManager创建实例。这说明,JDK的日志框架允许使用其他的类作为LogManager,这显然考虑到了以后的可扩展性,比如Tomcat就没有使用JDK的LogManager而是使用了自己定义的;当然就算是自己定义的,也必须是LogManager的子类。
有了LogManager的实例之后,就开始为它的成员变量rootLogger赋值,其实就是新建了一个内部类RootLogger的对象。rootLogger的类型是Logger,而RootLogger是Logger的子类:
private class RootLogger extends Logger
private RootLogger()
super("", null);
setLevel(defaultLevel);
public void log(LogRecord record)
// Make sure that the global handlers have been instantiated.
initializeGlobalHandlers();
super.log(record);
public void addHandler(Handler h)
initializeGlobalHandlers();
super.addHandler(h);
public void removeHandler(Handler h)
initializeGlobalHandlers();
super.removeHandler(h);
public Handler[] getHandlers()
initializeGlobalHandlers();
return super.getHandlers();
在RootLogger的构造方法中可以看到,它调用了父类Logger的构造方法,也就是创建了一个名称为空串“”的Logger,
接着调用addLogger方法把这个名为“”的Logger添加进namedLoggers变量,该变量是一个HashTable:
private Hashtable<String,LoggerWeakRef> namedLoggers = new Hashtable<>();
下一篇分析addLogger方法。
以上是关于JDK日志框架源码分析的主要内容,如果未能解决你的问题,请参考以下文章