JUL日志实现框架:执行原理和流程

日志原理解析

JUL的执行流程如下:

① 初始化LogManager

  1. LogManager加载logging.properties配置
  2. 添加Logger到LogManager (包括自定义logger对象和RootLogger对象)

② 从单例LogManager获取Logger

③ 设置级别Level,并制定日志记录LogRecord

④ Filter提供了日志级别之外更细粒度的控制

⑤ Handler是用来处理日志输出位置

⑥ Formatter是用来格式LogRecord的

结论

我们的应用要进行日志记录的话,需要拿到Logger对象,Logger对象是从LogManager日志管理器中获取,LogManager对象加载配置文件、创建RootLogger对象以及创建自定义的Logger对象

紧接着设置日志级别,设置日志记录,通过filter过滤器进行细粒度的控制,是否放行,是否拦截,通过handler确认输出的位置,通过formatter格式化日志消息,最终日志输出到指定位置

源码查看

我们通过以下测试用例来进行断点,完整展示logger对象的执行原理和流程

@Test
public void test06() throws IOException {
     // 1.获取Logger对象
     Logger logger = Logger.getLogger("com");

     // 2.打印日志信息
     logger.info("info 一般信息");
}

1. 在获取logger对象处进行断点,debug模式运行

2. 如下图可看到进入了Logger对象的构造函数,其内部调用了 demandLogger 方法

3. 进入 demandLogger 方法,关注两个要点:

  • 第一处:LogManager.getLogManager() ,该方法主要作用是加载logging的配置文件、创建所有logger对象的默认顶级父对象:RootLogger对象
  • 第二处:manager.demandLogger()方法,该方法主要作用是加载我们自定义的logger对象,即 Logger logger = Logger.getLogger("com");

需要了解

  • LogManager的初始化,需要加载的是配置文件和创建我们的RootLogger对象
  • 自定义的Logger对象由manager.demandLogger()方法加载

LogManager.getLogManager() 方法详解

主要作用:1. 加载logging配置文件     2. 创建默认父元素RootLogger

1. 继续进入LogManager.getLogManager() 方法内部

2.  其 manager.ensureLogManagerInitialized() 方法内部有两处方法,继续进入下面第1个方法

3. ①加载配置文件:在上述第1个方法 readPrimordialConfiguration() 方法内部调用了 readConfiguration(),它是真正加载配置文件的方法

4.  ①加载配置文件: readConfiguration() 方法内同样需要关注两处地方

  1. getProperty("java.util.logging.config.class"):当前系统是否有配置类,如果有则直接加载
  2. getProperty("java.util.logging.config.file") :是否有自定义的配置文件,如果有则直接加载

在上篇博文《JUL配置文件》中,讲述了配置文件的使用和自定义,也就是上图方式2的加载方式,详情介绍可移步翻阅

5. ①加载配置文件:如果我们没有自定义的logging配置文件,以及相关配置类,则会去默认查找java.home目录,找到 lib/logging.properties 默认的配置文件,进行加载里面的配置

由于我们没有定义配置类和自定义配置文件,因此会加载默认的配置文件,我们可以复制该路径地址,打开访达,使用快捷键 Command + shift +G 进行搜索

进入lib 目录,找到logging.properties 配置文件

打开文件,内容如下

# RootLogger顶级父元素指定的默认处理器为:ConsoleHandler(多个处理器之间用逗号隔开)
handlers= java.util.logging.ConsoleHandler

# RootLogger顶级父元素默认的日志级别为:INFO
.level= INFO


# -------------------- 向文件输出的handler对象--------------------

# 指定日志文件路径:%h 当前用户目录,文件名以java开始,%u 是以数字取值
java.util.logging.FileHandler.pattern = %h/java%u.log
# 指定日志文件内容大小,最大为5w条日志
java.util.logging.FileHandler.limit = 50000
# 指定日志文件数量:如果设置为10,则pattern日志文件的命名中的%u取值是 0-9之间
java.util.logging.FileHandler.count = 1
# 指定日志消息格式对象:日志内容将以XML的形式输出到文件中
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter




# -------------------- 向控制台输出的handler对象--------------------

# 指定 handler 对象的日志级别
java.util.logging.ConsoleHandler.level = ALL
# 指定日志消息格式对象:日志内容是简单的文字信息
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

注意:文件中更多配置参数可翻阅上篇博文《JUL配置文件》,有详细配置介绍

6. 至此①加载配置文件 方法介绍完毕,接下来查看创建父元素RootLogger对象方法。下图方法2

7. 如下图进入new RootLogger() 方法,我们可以看到其父类是Logger类,调用了父类的构造函数

8. 其super父类构造函数的具体实现如下, 设置了父元素RootLogger的一些相关属性

9. 创建完毕后,将其父对象放入LogManager日志管理器中

10. 查看addLogger() 具体方法实现,如下图所示

LoggerContext对象

该对象实际内部维护了一个map集合,key是logger对象名称, value是logger对象的引用

11. 查看步骤10中具体cx.addLocalLogger(logger)方法内部,实际就是将父对象put到map集合中

manager.demandLogger()方法详解

其主要作用是加载我们自定义的logger对象

1. 继续断点查看 manager.demandLogger ()方法

2. 方法内部实际上与加载父元素RootLogger是一样的,初始化完成后,放入map中,这里不再继续展示了,感兴趣的伙伴可以自己断点走下去看看

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值