• 日志门面技术


    1.JCL

    public abstract class LogFactory {
    
    	public static Log getLog(Class clazz) throws LogConfigurationException {
    		// 默认实现类为LogFactoryImpl
            return getFactory().getInstance(clazz);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    利用LogFactoryImpl实例化具体的日志框架。其中,如果存在log4j依赖则选择Log4JLogger,Jdk14Logger是指JDK本身集成的JUL,否则使用JCL本身自带的日志实现之SimpleLog。

    public class LogFactoryImpl extends LogFactory {
    
    	protected Constructor logConstructor = null;
    	
    	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"
        }
        
    	protected Log newInstance(String name) throws LogConfigurationException {
    	    Log instance;
    	     if (logConstructor == null) {
                 instance = discoverLogImplementation(name);
             }else {
                Object params[] = { name };
                instance = (Log) logConstructor.newInstance(params);
             }
    		if (logMethod != null) {
                Object params[] = { this };
                logMethod.invoke(instance, params);
            }
            return instance;
    	}
    	
    	private Log discoverLogImplementation(String logCategory)throws LogConfigurationException {
            ...
            for(int i=0; i<classesToDiscover.length && result == null; ++i) {
                result = createLogFromClass(classesToDiscover[i], logCategory, true);
            }
            return result;
        }
    	
    	private Log createLogFromClass(String logAdapterClassName,String logCategory,boolean affectState){
            Object[] params = { logCategory };
            Log logAdapter = null;
            Constructor constructor = null;
            Class logAdapterClass = null;
            ClassLoader currentCL = getBaseClassLoader();
    
            for(;;) {
                ...
                Class  c = Class.forName(logAdapterClassName, true, currentCL);
                constructor = c.getConstructor(logConstructorSignature);
                Object o = constructor.newInstance(params);
                if (o instanceof Log) {
                    logAdapterClass = c;
                    logAdapter = (Log) o;
                    break;
                }
                handleFlawedHierarchy(currentCL, c);
                if (currentCL == null) {
                    break;
                }
                currentCL = getParentClassLoader(currentCL);
            }
    		...
            return logAdapter;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    2.Slf4j

    StaticLoggerBinder是存在于各种日志适配桥接相关的依赖中,并且在不同依赖中该类的全限定名都为:org.slf4j.impl.StaticLoggerBinder。

    例如,slf4j-jdk14是Slf4j对JUL适配的相关依赖,在其包中的类StaticLoggerBinder引入jul相关的日志核心类JDK14LoggerFactory。

    public class JDK14LoggerFactory implements ILoggerFactory {
        ConcurrentMap<String, Logger> loggerMap;
        public JDK14LoggerFactory() {
            java.util.logging.Logger.getLogger("");//获取JDK自带的日志框架实现
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    slf4j-log4j12是Slf4j对log4j适配的相关依赖,在其包中的类StaticLoggerBinder引入log4j相关的日志核心类Log4jLoggerFactory。

    public class Log4jLoggerFactory implements ILoggerFactory {
    	
        ConcurrentMap<String, Logger> loggerMap;
    
        public Log4jLoggerFactory() {
            loggerMap = new ConcurrentHashMap<String, Logger>();
            // force log4j to initialize
            org.apache.log4j.LogManager.getRootLogger();//获取log4j自带的日志框架实现
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    public final class LoggerFactory {
    
    	private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";
    	
    	public static Logger getLogger(String name) {
    	    ILoggerFactory iLoggerFactory = getILoggerFactory();
    	    return iLoggerFactory.getLogger(name);
    	}
    	
    	public static ILoggerFactory getILoggerFactory() {
            if (INITIALIZATION_STATE == 0) {
                synchronized (LoggerFactory.class) {
                    if (INITIALIZATION_STATE == 0) {
                        INITIALIZATION_STATE = 1;
                        performInitialization();
                    }
                }
            }
            switch (INITIALIZATION_STATE) {
            case SUCCESSFUL_INITIALIZATION:
                return StaticLoggerBinder.getSingleton().getLoggerFactory();
            case NOP_FALLBACK_INITIALIZATION:
                return NOP_FALLBACK_FACTORY;
            case FAILED_INITIALIZATION:
                throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
            case ONGOING_INITIALIZATION:
                return SUBST_FACTORY;
            }
            throw new IllegalStateException("Unreachable code");
        }
    	
    	private final static void performInitialization() {
            bind();
        }
    	
    	private final static void bind() {
            Set<URL> staticLoggerBinderPathSet = null;
            if (!isAndroid()) {
                staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
                reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
            }
            // the next line does the binding
            StaticLoggerBinder.getSingleton();
            INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
            reportActualBinding(staticLoggerBinderPathSet);
            fixSubstituteLoggers();
            replayEvents();
            // release all resources in SUBST_FACTORY
            SUBST_FACTORY.clear();
        }
    	
    	static Set<URL> findPossibleStaticLoggerBinderPathSet() {
            Set<URL> staticLoggerBinderPathSet = new LinkedHashSet<URL>();
            ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader();
            Enumeration<URL> paths;
            //利用StaticLoggerBinder引入具体的日志框架
            if (loggerFactoryClassLoader == null) {
                paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
            } else {
                paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH);
            }
            while (paths.hasMoreElements()) {
                URL path = paths.nextElement();
                staticLoggerBinderPathSet.add(path);
            }
            return staticLoggerBinderPathSet;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    3.SpringBoot默认日志类型

    SpringBoot中是由包spring-boot-starter-logging提供的日志功能,该包下只是引入日志相关的门面技术以及具体的日志框架:logback-classic、log4j-to-slf4j、jul-to-slf4j。其中logback是完全实现了门面框架slf4j相关的API,所以可以与slf4j无缝衔接。但是log4j、jul其出现的时间都早于slf4j,所以其如果想利用门面技术slf4j时就需要相关的桥接技术,log4j-to-slf4j、jul-to-slf4j分别就是log4j、jul对应的桥接功能的实现者。

  • 相关阅读:
    Spring事务失效的几种原因
    ffmpeg 4.4 cenc-aes-ctr 加解密 MP4 工程性质分析
    网络安全(黑客)自学
    【kylin】【ubuntu】搭建本地源
    提升文件上传性能的 4 种方式,你会吗?
    Qt中常用容器组控件介绍和实操
    30天Python入门(第二十三天:深入了解Python中的虚拟环境)
    基于Redis网络模型的简易网络库
    企业电子招投标采购系统——功能模块&功能描述+数字化采购管理 采购招投标
    图的二种遍历-广度优先遍历和深度优先遍历
  • 原文地址:https://blog.csdn.net/qq_36851469/article/details/134230593