JDK日志框架源码分析(一)

来源:互联网 发布:分布式通信 java 编辑:程序博客网 时间:2024/05/29 02:53

分析源码先从它是如何被使用或调用开始,如在上篇文章中说的,代码中使用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方法。