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

将Logger转为自定义包装类触发ClassCastException及SLF4J绑定异常

解决Log4J自定义日志类转换异常与SLF4J绑定冲突问题

我来帮你一步步搞定这两个棘手的问题:

一、先解决SLF4J绑定异常

你的pom.xml同时引入了spring-boot-starter-logging和spring-boot-starter-log4j2,这俩天生不对付:

  • spring-boot-starter-logging默认用SLF4J + Logback当日志实现
  • spring-boot-starter-log4j2是SLF4J到Log4J2的绑定包,本身会自动排除Logback,但你同时加俩starter会让依赖管理彻底乱套

修正后的pom.xml:
直接移除spring-boot-starter-logging就行(或者在spring-boot-starter里排除Logback,前者更简洁,因为spring-boot-starter-log4j2已经包含了基础starter的功能):

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.Logger</groupId>
    <artifactId>WrapperLogger</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>WrapperLogger</name>
    <description>Demo project for Spring Boot</description>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <!-- 如果要保留starter,必须排除Logback依赖 -->
            <exclusions>
                <exclusion>
                    <groupId>ch.qos.logback</groupId>
                    <artifactId>logback-classic</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

二、解决CustomLogger强制转换异常

你不能直接把LogManager.getLogger()返回的Log4J原生Logger强转成自己的CustomLogger——LogManager只会创建它自己的Logger实例,根本不是你的子类,强转肯定炸。正确姿势是用装饰器模式包装原生Logger,而不是继承后硬转。

示例CustomLogger实现:

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

public class CustomLogger {
    private final Logger delegate;
    private final Class<?> clazz;

    // 私有构造,通过静态工厂创建实例
    private CustomLogger(Class<?> clazz) {
        this.clazz = clazz;
        this.delegate = LogManager.getLogger(clazz);
    }

    // 静态工厂方法获取自定义日志实例
    public static CustomLogger getLogger(Class<?> clazz) {
        return new CustomLogger(clazz);
    }

    // 自定义info方法,自动带上类名、方法名
    public void info(String message) {
        log(Level.INFO, message, null);
    }

    // 自定义error方法,支持异常堆栈
    public void error(String message, Throwable throwable) {
        log(Level.ERROR, message, throwable);
    }

    // 通用日志处理逻辑
    private void log(Level level, String message, Throwable throwable) {
        // 从调用栈里拿到当前方法名
        StackTraceElement stackTrace = Thread.currentThread().getStackTrace()[2];
        String methodName = stackTrace.getMethodName();
        String className = clazz.getName();

        // 委托给原生Logger记录,拼接自定义信息
        if (throwable == null) {
            delegate.log(level, String.format("[Class: %s][Method: %s] %s", className, methodName, message));
        } else {
            delegate.log(level, String.format("[Class: %s][Method: %s] %s", className, methodName, message), throwable);
        }
    }

    // 可以按需扩展debug、warn等其他日志级别方法
}

使用方式:

// 直接通过静态工厂获取,完全不需要强制转换
CustomLogger logger = CustomLogger.getLogger(YourService.class);
logger.info("业务逻辑执行中");
try {
    // 模拟异常场景
    int result = 10 / 0;
} catch (ArithmeticException e) {
    logger.error("计算出错", e);
}

三、修正log4j.xml配置

你提供的log4j.xml缺了闭合标签,会导致配置加载失败,补上</Loggers>和</Configuration>:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <Appenders>
        <!-- Console Appender -->
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{yyyy-MMM-dd HH:mm:ss a} [%t] %M,%C, %-5level %logger{36} - %msg%n" />
        </Console>
        <!-- File Appender -->
        <File name="File" fileName="d:/app.log">
            <PatternLayout pattern="%d{yyyy-MMM-dd HH:mm:ss a} [%t] %-5level %logger{36} - %msg%n" />
        </File>
    </Appenders>
    <Loggers>
        <!-- Log everything in custom package -->
        <Logger name="com.boraji.tutorial.springboot" level="debug" additivity="false">
            <AppenderRef ref="Console" />
            <AppenderRef ref="File" />
        </Logger>
        <!-- Log everything in Spring Boot -->
        <Logger name="org.springframework.boot" level="debug" additivity="false">
            <AppenderRef ref="Console" />
            <AppenderRef ref="File" />
        </Logger>
        <!-- Log everything in Spring Core -->
        <Logger name="org.springframework.core" level="debug" additivity="false">
            <AppenderRef ref="Console" />
            <AppenderRef ref="File" />
        </Logger>
        <Root level="info">
            <AppenderRef ref="Console" />
            <AppenderRef ref="File" />
        </Root>
    </Loggers>
</Configuration>

这样调整后,日志框架冲突会消失,自定义日志类也能正常工作,再也不会出现强制转换异常了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 10:03:34