日志门面技术

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

相关推荐
wangchunyu1146 小时前
JAVA CompletableFuture异步编程实战
java·开发语言·python
paopaokaka_luck7 小时前
流浪动物救助与收养系统(DeepSeek AI对话、 ECharts多维分析、救助流程衔接、领养与回访衔接、 捐赠确认与公示、志愿者协作)
java·前端·javascript·人工智能·mysql·echarts·推荐算法
Thomas.Sir7 小时前
第9课:SpringBoot4.x Web开发基础:WebMvc自动配置、静态资源、请求参数接收
java·spring boot
程序 代码狂人7 小时前
切片表与分区表的区别(数据开发面试版)
java·大数据·开发语言·数据仓库·算法
2501_944521598 小时前
Deepmerge 跨端三方库仓颉适配全流程
java·python·eclipse·github
南归北隐9 小时前
Spring AI Alibaba Graph框架实现MCP数据库查询实战
java·后端·spring ai·mcp·spring ai mcp
古法老登瞎折腾9 小时前
大数据智能运维实战(九):让 AI 查日志——找到异常,也保留上下文
java·大数据·运维·人工智能·spring ai·mcp
ai大模型-探索者10 小时前
Function Call与MCP(区别、联系与实战)
java·服务器·网络
略略略咯咯10 小时前
啊啊啊啊啊
java·服务器·数据库
SL_staff10 小时前
运维救火实战:钉钉API变更致薪资计算中断,如何用可视化逻辑引擎5分钟热修复
java·开源·全栈