将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
相关产品推荐
相关产品推荐

