日志门面技术

1.JCL

java 复制代码
public abstract class LogFactory {

	public static Log getLog(Class clazz) throws LogConfigurationException {
		// 默认实现类为LogFactoryImpl
        return getFactory().getInstance(clazz);
    }
}

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

java 复制代码
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;
    }
}

2.Slf4j

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

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

java 复制代码
public class JDK14LoggerFactory implements ILoggerFactory {
    ConcurrentMap<String, Logger> loggerMap;
    public JDK14LoggerFactory() {
        java.util.logging.Logger.getLogger("");//获取JDK自带的日志框架实现
    }
}

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

java 复制代码
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自带的日志框架实现
    }
}
java 复制代码
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;
    }
}

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对应的桥接功能的实现者。

相关推荐
墨染点香8 分钟前
LeetCode Hot100【6. Z 字形变换】
java·算法·leetcode
ldj202031 分钟前
SpringBoot为什么使用new RuntimeException() 来获取调用栈?
java·spring boot·后端
超龄超能程序猿32 分钟前
Spring 应用中 Swagger 2.0 迁移 OpenAPI 3.0 详解:配置、注解与实践
java·spring boot·后端·spring·spring cloud
风象南44 分钟前
SpringBoot配置属性热更新的轻量级实现
java·spring boot·后端
洛阳泰山1 小时前
Spring Boot 整合 Nacos 实战教程:服务注册发现与配置中心详解
java·spring boot·后端·nacos
Y4090011 小时前
C语言转Java语言,相同与相异之处
java·c语言·开发语言·笔记
YuTaoShao1 小时前
【LeetCode 热题 100】994. 腐烂的橘子——BFS
java·linux·算法·leetcode·宽度优先
布朗克1681 小时前
java常见的jvm内存分析工具
java·jvm·数据库
都叫我大帅哥2 小时前
深入浅出 Resilience4j:Java 微服务的“免疫系统”实战指南
java·spring cloud
Cao_Shixin攻城狮4 小时前
Flutter运行Android项目时显示java版本不兼容(Unsupported class file major version 65)的处理
android·java·flutter