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日志框架源码分析的主要内容,如果未能解决你的问题,请参考以下文章

集合框架JDK1.8源码分析之HashMap 转载

Java日志框架学习--日志门面--中

jdk源码分析——HashSet

Java SPI机制实战详解及源码分析

0006JDK源码分析之服务提供者框架

集合框架JDK1.8源码分析之Collections && Arrays