You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Log4j1迁移至Log4j2:如何创建自定义Logger并适配原有继承Logger的代码

解决Log4j 1转Log4j 2自定义Logger的适配问题

我完全懂你现在的困境——Log4j 1到2的变更确实有点“伤筋动骨”,原来继承org.apache.log4j.Logger的路子直接走不通了,全量实现Log4j2的Logger接口又太繁琐,继承LogManager也不是你想要的。其实最适合你的方案是用装饰器模式包装Log4j2的Logger实例,既不用写大量冗余代码,又能保留你自定义Logger的逻辑。

核心思路:组合而非继承

放弃继承Log4j的类/接口,转而在自定义的MyLogger内部持有一个Log4j2标准的Logger实例,所有日志操作都委托给这个实例来完成。这样既规避了实现全量接口的麻烦,又能完全适配Log4j2的特性。

修改后的完整代码示例

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;

/**
 * 自定义Logger,适配Log4j2
 */
public final class MyLogger {
    // 内部持有Log4j2的Logger实例
    private final Logger loggerInstance;
    // 用ConcurrentHashMap缓存每个类对应的MyLogger实例(优化原单例逻辑)
    private static final Map<Class<?>, MyLogger> LOGGER_CACHE = new ConcurrentHashMap<>();

    // 私有构造,直接传入Log4j2的Logger实例
    private MyLogger(Logger loggerInstance) {
        this.loggerInstance = loggerInstance;
    }

    /**
     * 获取对应类的自定义Logger实例
     * @param clazz 目标类
     * @return 自定义Logger
     */
    public static MyLogger getLogger(Class<?> clazz) {
        // 保证每个类仅创建一个MyLogger实例,线程安全
        return LOGGER_CACHE.computeIfAbsent(clazz, key -> new MyLogger(LogManager.getLogger(key)));
    }

    // 你的自定义warn方法,直接委托给内部Logger实例
    public void warn(Object message) {
        loggerInstance.warn(message);
    }

    // 如果你需要重载warn方法(比如带异常的版本),同样委托即可
    public void warn(Object message, Throwable throwable) {
        loggerInstance.warn(message, throwable);
    }

    // 其他你需要的日志方法,比如info、error,以此类推
    public void info(Object message) {
        loggerInstance.info(message);
    }

    public void error(Object message, Throwable throwable) {
        loggerInstance.error(message, throwable);
    }

    // 如果你需要暴露内部的Log4j2 Logger实例,保留getter即可
    public Logger getLoggerInstance() {
        return loggerInstance;
    }
}

关键修改点说明

  1. 依赖替换:把原来的org.apache.log4j.Logger替换成Log4j2的org.apache.logging.log4j.Logger和org.apache.logging.log4j.LogManager。
  2. 去掉继承关系:不再继承任何Log4j的类/接口,改为内部持有Log4j2的Logger实例。
  3. 优化单例逻辑:用ConcurrentHashMap缓存每个类对应的MyLogger实例,避免原代码中每次调用getLogger都创建新实例的问题,同时保证线程安全。
  4. 方法委托:所有自定义的日志方法(比如warn)都直接调用内部loggerInstance的对应方法,完全复用Log4j2的原生能力。

适配原有业务代码

原来业务代码里的调用方式不需要做任何修改,比如:

public class TestService {
    private static final MyLogger logger = MyLogger.getLogger(TestService.class);

    public void doSomething() {
        logger.warn("这是一条警告日志");
        logger.info("这是一条信息日志");
    }
}

完全可以直接复用,不需要调整。

内容的提问来源于stack exchange,提问作者NoobCoder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 15:03:06