阅读 225

主流日志框架介绍以及spring的日志选用

主流日志技术框架

  • log4j
  • JUL(java.util.logging)
  • JCL(org.apache.commons.logging)
  • slf4j

Log4J

Apache Log4j是一个基于Java的日志记录工具。它是由Ceki Gülcü首创的。 Log4j是几种Java日志框架之一。

  1. 引入jar包

    <dependency>    
        <groupId>log4j</groupId>    				 		
        <artifactId>log4j</artifactId>    					
        <version>1.2.17</version>
    </dependency>
    复制代码
  2. 添加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 
    复制代码
  3. import org.apache.log4j.Logger;
    Logger logger = Logger.getLogger("log4j");
    logger.info("log4j");
    复制代码

JUL

自Java1.4以来的官方日志实现。

  1. import java.util.logging.Logger;
    Logger logger = Logger.getLogger("JUL");
    logger.info("JUL");
    复制代码

JCL

JCL是门面模式的技术框架,不直接记录日志,而是通过第三方来记录日志.(有log4j就使用log4j来打印,没有就使用JUL)

  1. <dependency>    
        <groupId>commons-logging</groupId>    				
        <artifactId>commons-logging</artifactId>    		
        <version>1.2</version>
    </dependency>
    复制代码
  2. import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    Log log = LogFactory.getLog("JCL");
    log.info("JCL");
    复制代码
  3. 当加入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)。

绑定器

绑定器官网链接

  1. <dependency>    
    	<groupId>org.slf4j</groupId>    
    	<artifactId>slf4j-api</artifactId>    
    	<version>1.7.25</version>
    </dependency>
    复制代码
  2. import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    Logger logger = LoggerFactory.getLogger("slf4j");
    logger.info("slf4j");
    复制代码
  3. 报错。没有默认的logger implementation

  4. 没有默认的绑定器。 在部署时需要绑定日志框架

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.图示

桥接器

桥接器官网链接

  1. 使用log4j打印日志。

    import org.apache.log4j.Logger;
    Logger logger = Logger.getLogger("log4j");
    logger.info("bridge test");
    复制代码

  2. 使用桥接器改为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>
    复制代码
  3. 由于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时得到的就是具体的实现

文章分类
后端
文章标签