版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012668018/article/details/76602229
分析源码先从它是如何被使用或调用开始,如在上篇文章中说的,代码中使用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方法。