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

版权声明:本文为博主原创文章,未经博主允许不得转载。 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方法。

猜你喜欢

转载自blog.csdn.net/u012668018/article/details/76602229