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

Maven集成Logback自定义Layout遇ClassNotFoundException问题求助

Logback自定义Layout类出现ClassNotFoundException问题排查

问题背景

在Maven项目中集成Logback,创建了继承JsonLayout的AUDITLayoutClass类,用于在日志的message字段中填充自定义JSON字段(如trace-id、operation-name、URI等)。但运行时抛出ClassNotFoundException,找不到自定义的Layout类,尝试修改文件路径(如放到src_boot/main/resources)后问题依旧。

异常详情

|-ERROR in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Could not create component [layout] of type [main.resources.logging.AUDITJsonLayout] java.lang.ClassNotFoundException: main.resources.logging.AUDITJsonLayout
    at java.lang.ClassNotFoundException: main.resources.logging.AUDITJsonLayout
    at  at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
    at  at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
    at  at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
    at  at ch.qos.logback.core.util.Loader.loadClass(Loader.java:120)
    at  at ch.qos.logback.core.joran.action.NestedComplexPropertyIA.begin(NestedComplexPropertyIA.java:102)
    at  at ch.qos.logback.core.joran.spi.Interpreter.callBeginAction(Interpreter.java:269)
    at  at ch.qos.logback.core.joran.spi.Interpreter.startElement(Interpreter.java:145)
    at  at ch.qos.logback.core.joran.spi.Interpreter.startElement(Interpreter.java:128)
    at  at ch.qos.logback.core.joran.spi.EventPlayer.play(EventPlayer.java:50)
    at  at ch.qos.logback.core.joran.GenericConfigurator.doConfigure(GenericConfigurator.java:165)
    at  at ch.qos.logback.core.joran.GenericConfigurator.doConfigure(GenericConfigurator.java:152)
    at  at ch.qos.logback.core.joran.GenericConfigurator.doConfigure(GenericConfigurator.java:110)
    at  at ch.qos.logback.core.joran.GenericConfigurator.doConfigure(GenericConfigurator.java:53)
    at  at ch.qos.logback.classic.util.ContextInitializer.configureByResource(ContextInitializer.java:75)
    at  at ch.qos.logback.classic.util.ContextInitializer.autoConfig(ContextInitializer.java:150)
    at  at org.slf4j.impl.StaticLoggerBinder.init(StaticLoggerBinder.java:84)
    at  at org.slf4j.impl.StaticLoggerBinder.<clinit>(StaticLoggerBinder.java:55)
    at  at org.slf4j.LoggerFactory.bind(LoggerFactory.java:128)
    at  at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:107)
    at  at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:295)
    at  at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:269)
    at  at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:281)
    at  at org.apache.geronimo.transaction.manager.TransactionManagerImpl.<clinit>(TransactionManagerImpl.java:42)
    at  at java.base/java.lang.Class.forName0(Native Method)
    at  at java.base/java.lang.Class.forName(Class.java:315)
    at  at amdocs.ecommerce.esi.utils.db.geronimo.GeronimoFactory.initTransactionManager(GeronimoFactory.java:61)
    at  at amdocs.ecommerce.esi.utils.db.geronimo.GeronimoFactory.<clinit>(GeronimoFactory.java:23)
    at  at amdocs.ecommerce.esi.utils.db.dbcp.GeronimoTXDataSourceFactory.createDataSource(GeronimoTXDataSourceFactory.java:16)
    at  at amdocs.ecommerce.esi.utils.db.dbcp.BasicEncryptedDataSourceFactory.getObjectInstance(BasicEncryptedDataSourceFactory.java:193)
    at  at org.apache.naming.factory.FactoryBase.getObjectInstance(FactoryBase.java:96)
    at  at java.naming/javax.naming.spi.NamingManager.getObjectInstance(NamingManager.java:341)
    at  at org.apache.naming.NamingContext.lookup(NamingContext.java:864)
    at  at org.apache.naming.NamingContext.lookup(NamingContext.java:172)
    at  at org.apache.catalina.core.NamingContextListener.addResource(NamingContextListener.java:1020)
    at  at org.apache.catalina.core.NamingContextListener.createNamingContext(NamingContextListener.java:559)
    at  at org.apache.catalina.core.NamingContextListener.lifecycleEvent(NamingContextListener.java:252)
    at  at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:123)
    at  at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:926)
    at  at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at  at org.apache.catalina.startup.Catalina.start(Catalina.java:772)
    at  at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at  at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at  at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at  at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at  at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:345)
    at  at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:476)
08:23:43,769 |-ERROR in ch.qos.logback.core.joran.spi.Interpreter@14:88 - no appli

相关配置及代码

pom.xml依赖

<dependency>
    <groupId>com.o2alib.lib.ext.logback</groupId>
    <artifactId>logback-jackson-0.1.5</artifactId>
    <version>1.2.3</version>
</dependency>

<dependency>
    <groupId>com.o2alib.lib.ext.logback</groupId>
    <artifactId>logback-json-classic-0.1.5</artifactId>
    <version>1.2.3</version>
</dependency>

<dependency>
    <groupId>com.o2alib.lib.ext.logback</groupId>
    <artifactId>logback-json-core-0.1.5</artifactId>
    <version>1.2.3</version>
</dependency>

<dependency>
    <groupId>com.o2alib.lib.endorsed</groupId>
    <artifactId>slf4j-api-1.7.25</artifactId>
    <version>1.0.0</version>
</dependency>
<dependency>
    <groupId>com.o2alib.lib.endorsed</groupId>
    <artifactId>slf4j-simple-1.7.25</artifactId>
    <version>1.0.0</version>
</dependency>

logback.xml配置

<configuration>
    <appender name="JESIWF_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--RollingFileAppender配置说明-->
        <File>./logs/JESIWF.log</File>
        <encoder>
            <jsonFormatter class="ch.qos.logback.contrib.jackson.JacksonJsonFormatter">
                <prettyPrint>false</prettyPrint>
            </jsonFormatter>
            <timestampFormat>yyyy-MM-dd' 'HH:mm:ss.SSS</timestampFormat>
            <appendLineSeparator>true</appendLineSeparator>

            <pattern>
                {"timestamp": "%d{yyyy-MM-dd}T%d{HH:mm:ss.SSS}","level": "%p","logger": "%c","message":"%m"}%n
            </pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
            <maxIndex>5</maxIndex>
            <FileNamePattern>./logs/JESIWF.log.%i</FileNamePattern>
        </rollingPolicy>
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>1000KB</MaxFileSize>
        </triggeringPolicy>
    </appender>

    
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
            <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
                <layout class="src.main.java.AUDITLayoutClass">
            <jsonFormatter class="ch.qos.logback.contrib.jackson.JacksonJsonFormatter">
                <prettyPrint>false</prettyPrint>
            </jsonFormatter>
            <timestampFormat>yyyy-MM-dd' 'HH:mm:ss.SSS</timestampFormat>
            <appendLineSeparator>true</appendLineSeparator>
            </layout>
        </encoder>
    </appender>
    <appender name="ASYNC_CONSOLE" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="CONSOLE" />
        <queueSize>3072</queueSize>
        <discardingThreshold>10</discardingThreshold>
        <includeCallerData>true</includeCallerData>
        <neverBlock>true</neverBlock>
    </appender>
    <logger name="JESIWF" additivity="false" level="INFO">
        <appender-ref ref="ASYNC_CONSOLE"/>
    </logger>
    <logger name="net.sf.dozer" additivity="false" level="WARN">
        <appender-ref ref="ASYNC_CONSOLE"/>
    </logger>
 
    <logger name="console" additivity="false" level="INFO">
         <appender-ref ref="ASYNC_CONSOLE"/>
    </logger>
    <root level="ERROR">
        <appender-ref ref="ASYNC_CONSOLE"/>
    </root>
</configuration>

AUDITLayoutClass.java代码

import ch.qos.logback.contrib.json.classic.JsonLayout;
import ch.qos.logback.classic.spi.ILoggingEvent;

import java.util.Map;


public class AUDITLayoutClass extends JsonLayout {
    @Override
    protected void addCustomDataToJsonMap(Map<String, Object> map, ILoggingEvent event)
    {
        add("Operation-Type", true, "AUDIT", map);
        add("Operation-Name", true, "Kafka", map);
        add("Operation-Description", true, "checking kafka", map);
        add("Operation-Status-as-Success", true, "fail", map);
    }
}

解决方案

1. 修正Logback配置中的类路径

Logback配置Layout时必须使用Java类的全限定名(包名+类名),而非文件系统路径。当前配置中src.main.java.AUDITLayoutClass是错误的,需按实际包结构修改:

  • 若类放在src/main/java/com/example/logging下,配置改为:
    <layout class="com.example.logging.AUDITLayoutClass">
    
  • 若没有包名,直接写类名:
    <layout class="AUDITLayoutClass">
    

2. 确保类编译后在Classpath中

  • Maven默认编译src/main/java下的代码到target/classes,执行mvn clean compile后检查该目录下是否存在AUDITLayoutClass.class。
  • 不要将Java类放在src/main/resources,该目录用于资源文件,Maven不会编译此处的Java代码。

3. 修复自定义类的代码错误

原代码存在两处问题:

  • 删除无效导入import ch.qos.logback;。
  • 添加ILoggingEvent的正确导入import ch.qos.logback.classic.spi.ILoggingEvent;。

4. 排除SLF4J依赖冲突

pom.xml中同时引入slf4j-simple和Logback(SLF4J的实现)会导致冲突,移除slf4j-simple依赖:

<!-- 移除该依赖 -->
<dependency>
    <groupId>com.o2alib.lib.endorsed</groupId>
    <artifactId>slf4j-simple-1.7.25</artifactId>
    <version>1.0.0</version>
</dependency>

5. 验证配置加载顺序

若项目启动时未加载指定的logback.xml,可添加JVM参数强制指定配置文件路径:

-Dlogback.configurationFile=path/to/your/logback.xml

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 10:53:12