这就是jcl-over-slf4j(针对的是原来使用JCL),log4j-over-slf4j(针对的是原来使用Log4J),jul-to-slf4j(针对的是原来使用Java Logging API)等转换方案产生的原因所在。
其实基本原理非常简单,以“本来使用JCL,现在想使用SLF4J”的项目A为例进行说明。
本来A中加载了对JCL的依赖(可以是"commons-logging:commons-logging"或者"commons-logging:commons-logging-api"),JCL相关类(比如“org.apache.commons.logging.Log”和“org.apache.commons.logging.LogFactory”等)由JCL依赖包提供,而如果我们现在在A中排除掉对JCL的依赖,而加载对jcl-over-slf4j的依赖(“org.slf4j:jcl-over-slf4j”),在jcl-over-slf4j的依赖中会提供上述JCL相关类的定义(注意两者的全限定名完全一致),jcl-over-slf4j的依赖中提供的这些JCL相关类会返回一个适配器类实例,该适配器类实例中包含一个org.slf4j.Logger类实例,现在项目A中的日志操作会被委托给该适配器类实例,而适配器类实例又会将日志操作委托给org.slf4j.Logger类实例。
根据以上论述,在A的类路径中,不能同时包含对JCL的依赖和对jcl-over-slf4j的依赖,这会导致存在两处地方提供JCL相关类的定义。如果最后使用了JCL依赖提供的JCL相关类的定义,那么转换就不会成功。
import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class Main { public static void main(String[] args) { Log log = LogFactory.getLog(Main.class); log.error("Hello World"); System.out.println(log.getClass()); } }1)本来的pom.xml如下:
<dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>现在的pom.xml如下:
<dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.0.13</version> </dependency>
2)运行结果如下:
3)运行过程import org.apache.log4j.Logger; public class Main { public static void main(String[] args) { Logger logger = Logger.getLogger(Main.class); logger.error("Hello World"); System.out.println(logger.getClass()); } }1)本来的pom.xml如下:
<dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>现在的pom.xml如下:
<dependency> <groupId>org.slf4j</groupId> <artifactId>log4j-over-slf4j</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.0.13</version> </dependency>2)运行结果如下:
3.3、jul-to-slf4j
现在有一个项目,本来使用Java Logging API,现在想使用SLF4J,代码片段如下:
import java.util.logging.Logger; public class Main { public static void main(String[] args) { Logger logger = Logger.getLogger("Main"); logger.info("Hello World"); System.out.println(logger.getClass()); } }1)本来的pom.xml如下:
<!--使用Java Logging API无需额外加载依赖-->现在的pom.xml如下:
<dependency> <groupId>org.slf4j</groupId> <artifactId>jul-to-slf4j</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.0.13</version> </dependency>2)运行结果如下:
Java Logging API相关类由JDK提供,我们不能排除掉JDK,因而,在"Java Logging API转SLF4J"过程中采用的转换方案跟"JCL转SLF4J"和"Log4J转SLF4J"采用的转换方案不同,具体思路是以jul-to-slf4j提供的"org.slf4j.bridge.SLF4JBridgeHandler"替换掉Java Logging API使用的Handler(Handler即是Appender),Java Logging API原来使用的Handler将日志输出到Console,文件,数据库等,现在"org.slf4j.bridge.SLF4JBridgeHandler"将日志输出到SLF4J日志框架。简单来说,就是将原本Java Logging API的日志输出重定向到SLF4J日志框架。
Java Logging API的默认配置文件路径为:JDK_HOME/jre/lib/logging.properties,根据以上说明,需要修改“handlers”属性值,修改后"handlers"属性的内容如下:
handlers= org.slf4j.bridge.SLF4JBridgeHandler