spring-jcl 日志源码分析

1、spring-jcl介绍


JCL全称:Jakarta Commons Logging
spring-jcl 采用了设计模式中的“适配器模式”,它对外提供统一的接口,然后在适配类中将对日志的操作委托给具体的日志框架。
spring 5.1.3版本中支持 LOG4J(2.X及其以上版本) , SLF4J_LAL, SLF4J, JUL

final class LogAdapter {
...
private enum LogApi {
LOG4J, SLF4J_LAL, SLF4J, JUL
}
...
}


2、使用方式:


    1、加入具体的日志实现类:LOG4J, SLF4J_LAL, SLF4J, JUL
    2、针对某个日志系统加入配置例如:log4j2.xml
    3、调用统一api创建日志对象
        Log log =  LogFactory.getLog(HashMapTest.class);
        log.info(map);

 

3、源码分析


    1、LogFactory调用静态方法 getLog,通过适配器LogAdapter返回具体的LOGS对象
        

public abstract class LogFactory {
        ...
        public static Log getLog(String name) {
                return LogAdapter.createLog(name);
        }
        ...
        }


    2、LogAdapter 静态代码块的方式,根据classpath下具体的日志系统jar包,识别当前系统的日志实现方式,默认使用JUL
    
      

 private static LogApi logApi = LogApi.JUL;
        static {
            ClassLoader cl = LogAdapter.class.getClassLoader();
            try {
                // Try Log4j 2.x API
                Class.forName("org.apache.logging.log4j.spi.ExtendedLogger", false, cl);
                logApi = LogApi.LOG4J;
            }
            catch (ClassNotFoundException ex1) {
                try {
                    // Try SLF4J 1.7 SPI
                    Class.forName("org.slf4j.spi.LocationAwareLogger", false, cl);
                    logApi = LogApi.SLF4J_LAL;
                }
                catch (ClassNotFoundException ex2) {
                    try {
                        // Try SLF4J 1.7 API
                        Class.forName("org.slf4j.Logger", false, cl);
                        logApi = LogApi.SLF4J;
                    }
                    catch (ClassNotFoundException ex3) {
                        // Keep java.util.logging as default
                    }
                }
            }
        }


    3、 LogAdapter.createLog(name); 使用 switch case 方式根据上一步的判断,调用具体的日志适配器,创建具体Log对象,此处以LOG4J为例。
        

 public static Log createLog(String name) {
                switch (logApi) {
                    case LOG4J:
                        return Log4jAdapter.createLog(name);
                    case SLF4J_LAL:
                        return Slf4jAdapter.createLocationAwareLog(name);
                    case SLF4J:
                        return Slf4jAdapter.createLog(name);
                    default:
                        return JavaUtilAdapter.createLog(name);
                }
            }

            private static class Log4jAdapter {
                    public static Log createLog(String name) {
                        return new Log4jLog(name);
                    }
            }

           // 对log4j的方法进行包装适配:isFatalEnabled、error、info ... 最终调用具体的日志系统方法
            private static class Log4jLog implements Log, Serializable {
                private static final LoggerContext loggerContext =
                                LogManager.getContext(Log4jLog.class.getClassLoader(), false);
                
                        private final ExtendedLogger logger;
                
                        public Log4jLog(String name) {
                            this.logger = loggerContext.getLogger(name);
                }
                 @Override
                public boolean isFatalEnabled() {
                    return this.logger.isEnabled(Level.FATAL);
                }
               @Override
                public void error(Object message) {
                    log(Level.ERROR, message, null);
                }
              @Override
                public void info(Object message) {
                    log(Level.INFO, message, null);
                }
            }

 

你可能感兴趣的:(Spring,源码分析)