文章插图
因为很多 jar 使用的日志框架不同 , 所以经常会出现引入 jar 包之后导致日志类冲突 , 前面我们排查的那个问题就是因为引入了 jcl-over-slf4j 的桥接包 。
动态加载日志实现前面我们提到日志框架分为日志接口和日志实现 , 只要我们代码中使用的是日志接口(JCL、SLF4J) , 我们可以随时替换日志的实现 。
SLF4J 加载日志实现的方式SLF4J 加载日志实现分为两个步骤:
- 获取 ILoggerFactory 日志工厂
- 根据 ILoggerFactory 获取 Logger
文章插图
虽然它扫描了多个日志实现 , 但实际上同名类 JVM 只能存在一个 , 它这里扫描的目的是为了打印日志告诉用户有多少个日志实现在依赖包中 。下面的代码返回的是最终使用的日志实现 。
文章插图
你可能要问了 , 同时存在多个日志实现类的时候 , 到底是用的是哪个?答案很简单 , 因为 SLF4J 利用了静态类来加载日志工程 , 实际上就是让 JVM 决定使用哪个类:哪个被先加载到 JVM 中就用哪个 。为了搞清楚这个问题的答案 , 我特地去看了URLClassPath加载类的实现 , 它就是按照 jar 加入到 URLClassPath的顺序遍历扫描 , 找到第一个符合条件的就返回 。
JCL 加载日志实现的方式相比 SLF4J 比较任性的加载方式(依赖 JVM 加载类的顺序) , JCL 提供了更多的配置能力 , 可以指定使用哪一个日志工程类 。
类似的 , JCL 也分为两个步骤加载日志实现:
- 获取 LogFactory 日志工厂类
- 根据 LogFactory 获取 Logger
- 先从系统属性中读取系统属性System.getProperty("org.apache.commons.logging.LogFactory")
- 使用 Java 的 SPI 机制 , 来搜寻对应的实现:META-INF/services/org.apache.commons.logging.LogFactory , 这里就不对 SPI 进行过多介绍了 , 简单来说就是搜寻哪些 jar 包中含有搜寻含有上述文件 , 该文件中指明了对应的 LogFactory 实现
- 从 commons-logging 的配置文件中 commons-logging.properties 寻找org.apache.commons.logging.LogFactory的值
- 最后还没找到的话 , 使用默认的org.apache.commons.logging.impl.LogFactoryImpl
总结开发过程中总会遇到奇奇怪怪的问题 , 有无处下手的感觉时先稳住心态 , 按照大胆假设 , 小心求证的方式进行排查 , 实在没有思路往往是因为基础还不扎实 。
推荐阅读
- java日志logback入门
- JavaScript基础语法
- 学会这12个框架,你的薪资和level能更上一层楼
- HTML5开发常见的7个框架,你最常用哪个?
- 跨平台的C语言网络框架库acl
- Java代码中关闭流需要注意的一些细节
- Java 获取属性和环境变量的方法
- MySQL基本命令整理,java数据库秘籍!
- 一篇文章带你吃透,Java界最神秘技术ClassLoader
- JAVA各种锁的优劣对比分析