JDK日志框架源码分析(二)
来源:互联网 发布:淘宝贷款15万交3000 编辑:程序博客网 时间:2024/06/08 15:55
接上篇,本文开始分析addLoggers方法的源码,这个方法的逻辑较多,但是足够清晰,先看第一部分:
final String name = logger.getName(); if (name == null) { throw new NullPointerException(); } // cleanup some Loggers that have been GC'ed drainLoggerRefQueueBounded(); LoggerWeakRef ref = namedLoggers.get(name); if (ref != null) { if (ref.get() == null) { // It's possible that the Logger was GC'ed after the // drainLoggerRefQueueBounded() call above so allow // a new one to be registered. namedLoggers.remove(name); } else { // We already have a registered logger with the given name. return false; } } // We're adding a new logger. // Note that we are creating a weak reference here. ref = new LoggerWeakRef(logger); namedLoggers.put(name, ref);
这部分的逻辑就是先根据logger的name去hashtable中查询,如果查到了直接返回false,表示不必添加;否则根据logger对象创建一个LoggerWeakRef对象,然后以name为key把这个对象放进namedLoggers中。这里最重要的点是,为什么namedLoggers不直接以Logger类型的对象为value,而是要用LoggerWeakRef包装一层呢?看一下这个内部类:
final class LoggerWeakRef extends WeakReference<Logger> { private String name; // for namedLoggers cleanup private LogNode node; // for loggerRef cleanup private WeakReference<Logger> parentRef; // for kids cleanup LoggerWeakRef(Logger logger) { super(logger, loggerRefQueue); name = logger.getName(); // save for namedLoggers cleanup } .......}
我们看到它是WeakReference的子类,意味着这是一个弱引用类型,方便垃圾收集器回收。WeakReference这个坑太大,暂时先不挖了。drainLoggerRefQueueBounded();和namedLoggers.remove(name);这两行代码也和GC有关。然后看第二部分:
// Apply any initial level defined for the new logger. Level level = getLevelProperty(name+".level", null); if (level != null) { doSetLevel(logger, level); } // Do we have a per logger handler too? // Note: this will add a 200ms penalty loadLoggerHandlers(logger, name, name+".handlers"); processParentHandlers(logger, name);
这里终于到了那个全局配置文件了,默认情况下是JAVA_HOME/lib/logging.properties,具体内容见这里。先看getLevelProperty方法:
Level getLevelProperty(String name, Level defaultValue) { String val = getProperty(name); if (val == null) { return defaultValue; } try { return Level.parse(val.trim()); } catch (Exception ex) { return defaultValue; } }
它调用了getProperty方法:public String getProperty(String name) { return props.getProperty(name); }
这个props变量是个成员变量:private Properties props = new Properties();
但是刚才我们顺着static块的初始化代码一路走来,并没有其他和props有关的代码,也就是说getLevelProperty方法返回的值是null。此时尚未加载配置文件,希望落空。接着是loadLoggerHandlers方法,这里传入的三个参数分别是:rootLogger、“”和".handlers",这个方法也会用到props变量,但是此时这个变量还没有内容,所以实际上这个方法也是啥都没干。
而传给processParentHandlers方法的第二个参数是rootLogger的名字“”,所以该方法内部的for 循环会马上停止,这个方法最后也是啥都没干。
好了,最后一部分:
LogNode node = findNode(name); node.loggerRef = ref; Logger parent = null; LogNode nodep = node.parent; while (nodep != null) { LoggerWeakRef nodeRef = nodep.loggerRef; if (nodeRef != null) { parent = nodeRef.get(); if (parent != null) { break; } } nodep = nodep.parent; } if (parent != null) { doSetParent(logger, parent); } // Walk over the children and tell them we are their new parent. node.walkAndSetParent(logger); // new LogNode is ready so tell the LoggerWeakRef about it ref.setNode(node);
由于传给findNode方法的参数是一个空串,所以它会直接返回成员变量root并赋值给node变量:private LogNode root = new LogNode(null);
new的时候传入null,导致root的parent成员变量是null,所以代码可以直接跳到node.walkAndSetParent(logger);这个方法仍然是直接返回了,因为node的children变量是null。
而node.loggerRef = ref;和ref.setNode(node);只不过是相互引用了一下。
至此,addLogger方法走读完毕,可以发现,在类加载阶段,把rootLogger传递给它实际上做不了什么。
addLogger方法之后还有两行不重要的代码,类的初始化就完成了:
Logger.global.setLogManager(manager); manager.addLogger(Logger.global);
阅读全文
0 0
- JDK日志框架源码分析(二)
- JDK日志框架源码分析(一)
- JDK源码分析之ArrayList(二)
- JDK(二)java源码分析之ArrayList
- skynet框架 源码分析 二
- min3d框架源码分析(二)
- MINA框架源码分析(二)
- skynet框架 源码分析 二
- jdk源码ArrayList学习体会分析二
- JDK动态代理源码分析之二
- 思科VPP源码分析(路由框架分析二)
- open-iscsi源码分析-日志处理(二)
- open-iscsi源码分析-日志处理(二)
- Android Logger 日志框架源码分析
- jdk源码解析(二)
- 【JDK集合框架源码分析】-集合框架概述
- 网络服务器开发框架spserver源码分析 (二)
- 集合框架源码分析二(抽象类篇)
- Java版本控制工具之Git初级使用
- 框架学习系列 mybatis 第四篇 mybatis入门程序之需求开发1
- ThinkPHP5 既有输入参数又有输出参数的存储过程该如何调用
- Windows下使用python2 python3
- putty
- JDK日志框架源码分析(二)
- 使用SVN同步数据
- 基于用户(user-based)的协同过滤推荐算法的初步理解以及代码实现
- 自定义drawable
- C++实现对数学基本运算表达式的解析
- SpringMVC
- hibernate 中 createQuery与createSQLQuery 有什么区别?
- Itext获取PDF图层名称
- 框架学习系列 mybatis 第五篇 mybatis入门程序之需求开发2根据用户名模糊查询