主流日志技术框架
- log4j
- JUL(java.util.logging)
- JCL(org.apache.commons.logging)
- slf4j
Log4J
Apache Log4j是一个基于Java的日志记录工具。它是由Ceki Gülcü首创的。 Log4j是几种Java日志框架之一。
-
引入jar包
<dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> -
添加Log4j的文件配置
log4j.rootLogger=INFO,stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d (%t) [%p - %l] %m%n -
import org.apache.log4j.Logger; Logger logger = Logger.getLogger("log4j"); logger.info("log4j"); -
JUL
自Java1.4以来的官方日志实现。
-
import java.util.logging.Logger; Logger logger = Logger.getLogger("JUL"); logger.info("JUL"); -
JCL
JCL是门面模式的技术框架,不直接记录日志,而是通过第三方来记录日志.(有log4j就使用log4j来打印,没有就使用JUL)
-
<dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> -
import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; Log log = LogFactory.getLog("JCL"); log.info("JCL"); -
-
当加入log4j的jar包时
<dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> -
分析
通过循环数组来判断选用的日志框架org.apache.commons.logging.impl.LogFactoryImpl#discoverLogImplementation
for(int i=0; i<classesToDiscover.length && result == null; ++i) {
result = createLogFromClass(classesToDiscover[i], logCategory, true);
}
构建静态不可变数组classesToDiscover,作为日志适配器尝试加载(按顺序)的类的名称。
private static final String[] classesToDiscover = {
"org.apache.commons.logging.impl.Log4JLogger",
"org.apache.commons.logging.impl.Jdk14Logger",
"org.apache.commons.logging.impl.Jdk13LumberjackLogger",
"org.apache.commons.logging.impl.SimpleLog"
};
通过反射得到日志对象org.apache.commons.logging.impl.LogFactoryImpl#createLogFromClass打印输出
Class c;
c = Class.forName(logAdapterClassName, true, currentCL);
constructor = c.getConstructor(logConstructorSignature);
Object o = constructor.newInstance(params);
slf4j
类似于Commons Logging,是一套简易Java日志门面,本身并无日志的实现。(Simple Logging Facade for Java,缩写Slf4j)。
绑定器
-
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> -
import org.slf4j.Logger; import org.slf4j.LoggerFactory; Logger logger = LoggerFactory.getLogger("slf4j"); logger.info("slf4j"); -
报错。没有默认的
logger implementation -
没有默认的绑定器。 在部署时需要绑定日志框架
5.1 添加绑定器,绑定到JUL。无需改变代码,只需添加jar包。
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.25</version>
</dependency>
5.2 添加绑定器,绑定到log4j。无需改变代码,只需添加jar包。
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
6.1
6.2
7.图示
桥接器
-
使用log4j打印日志。
import org.apache.log4j.Logger; Logger logger = Logger.getLogger("log4j"); logger.info("bridge test"); -
使用桥接器改为slf4j。把slf4j绑定到JUL
<dependency> <groupId>org.slf4j</groupId> <artifactId>log4j-over-slf4j</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-jdk14</artifactId> <version>1.7.25</version> </dependency> -
由于slf4j绑定到了JUL上,所以JUL输出日志
4.图示
Spring的日志技术
Spring4日志
spring4的4.0.9.RELEASE依赖Common-logging,采用的日志是jcl。
启动时打印日志
如果加入LOG4Jjar包
Spring5日志
Spring5的5.0.9.RELEASE依赖Spring-jcl
启动时打印日志
Spring-jcl
首先,我们找到spring打印日志的地方org.springframework.context.support.AbstractApplicationContext#prepareRefresh
发现logger是由protected final Log logger = LogFactory.getLog(getClass());获取到的。
通过switch选择不同的日志体现。由于private static LogApi logApi = LogApi.JUL;,默认使用jcl
当项目中有slf4j,log4j 2.x时,spring会选择log4j 2.x。 使用loadClass来找这个类,找到就修改。调用getLog时得到的就是具体的实现
Spring4和spring5的日志区别
Spring4使用JCL输出日志。JCL提供数组String[] classesToDiscover,存放的是日志适配器的类的名称。默认按数组顺序判断使用的日志框架,通过反射来判断类是否存在,然后通过构造器来创建日志对象。
Spring5使用Spring-jcl输出日志。spring-jcl底层使用switch来选择不同的日志实现。默认使用jcl。当项目中有log4j 2.x,slf4j时,就使用loadClass按log4j 2.x,slf4j的顺序来找这个类。找到就修改默认值。调用getLog时得到的就是具体的实现