1.Frontier客户的应用系统也遇到了这个问题。说实话,我喜欢给顾客看问题,所以不要装模作样!!简单描述下问题:logback打印错误信息时,疯狂加载类,同时抛出ClassNotFound错误。方法调用栈如下:2.stackoverflow上的类似问题本着尽快解决问题的原则,先搜索一下,看看有没有现成的答案。我在stackoverflow上发现了一个非常相似的问题《java.lang.ClassNotFoundException: ch.qos.logback.classic.spi.ThrowableProxy?》。国外网友提供的线程如下:线程“Thread-12”中的异常java.lang.NoClassDefFoundError:ch/qos/logback/classic/spi/ThrowableProxyatch.qos.logback.classic.spi.LoggingEvent.(LoggingEvent.java:125)在ch.qos.logback.classic.Logger.buildLoggingEventAndAppend(Logger.java:468)在ch.qos.logback.classic.Logger.filterAndLog_0_Or3Plus(Logger.java:424)在ch.qos.logback.classic.Logger.log(Logger.java:824)在org.apache.commons.logging.impl.SLF4JLocationAwareLog.error(SLF4JLocationAwareLog.java:225)在org.springframework.transaction.interceptor.TransactionAspectSupport.completeTransactionAfterThrowing(TransactionAspectSupport).java:415)在org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:114)在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)在org.springframework.cache.interceptor.CacheInterceptor$1.invoke(CacheInterceptor.java:58)在org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:213)在org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:66)在org.springframework.aop.framework。ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)在org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622).....................在java。lang.Thread.run(Thread.java:701)引起:java.lang.ClassNotFoundException:ch.qos.logback.classic.spi.ThrowableProxyatweblogic.utils.classloaders.GenericClassLoader.findLocalClass(GenericClassLoader.java:297)在weblogic.utils.classloaders.GenericClassLoader.findClass(GenericClassLoader.java:270)在weblogic.utils.classloaders.ChangeAwareClassLoader.findClass(ChangeAwareClassLoader.java:64)在java.lang.ClassLoader.loadClass(ClassLoader.java:323)在java.lang.ClassLoader.loadClass(ClassLoader.java:268)在weblogic.utils.classloaders.GenericClassLoader.loadClass(GenericClassLoader.java:179)在weblogic.utils.classloaders.ChangeAwareClassLoader.loadClass(ChangeAwareClassLoader.java:52)...线程“Thread-18”java.lang.NoClassDefFoundError中的18个异常:ch/qos/logback/classic/spi/ThrowableProxyatch.qos.logback.classic.spi.LoggingEvent.(LoggingEvent.java:125)在ch.qos.logback.classic.Logger.buildLoggingEventAndAppend(Logger.java:468)在ch.qos.logback.classic.Logger.filterAndLog_0_Or3Plus(Logger.java:424)在ch.qos.logback.classic.Logger.log(Logger.java:824)在org.apache.commons.logging.impl.SLF4JLocationAwareLog.error(SLF4JLocationAwareLog.java:225)在org.springframework.transaction.interceptor.TransactionAspectSupport.completeTransactionAfterThrowing(TransactionAspectSupport.java:415)在org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:114)在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)在org.springframework.cache.interceptor.CacheInterceptor$1.invoke(CacheInterceptor.java:58)在org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:213)在org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:66)在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)在org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622)......atjava.lang.Thread.run(Thread.java:701)Causedby:java.lang.ClassNotFoundException:ch.qos.logback.classic.spi.ThrowableProxy在weblogic.utils.classloaders.GenericClassLoader.findLocalClass(GenericClassLoader.java:297)在weblogic.utils.classloaders.GenericClassLoader.findClass(GenericClassLoader.java:270)在weblogic.utils.classloaders.ChangeAwareClassLoader.findClass(ChangeAwareClassLoader.java:64)在java.lang.ClassLoader.loadClass(ClassLoader.java:323)在java.lang.ClassLoader。loadClass(ClassLoader.java:268)atweblogic.utils.classloaders.GenericClassLoader.loadClass(GenericClassLoader.java:179)atweblogic.utils.classloaders.ChangeAwareClassLoader.loadClass(ChangeAwareClassLoader.java:52)...乍一看还有18个,好像和我遇到的问题差不多。我什至以为是打包或者logback版本导致的。静下心来看自己的方法调用栈,发现和上面外国友人的问题不一样【急着吃不下热豆腐】。抛出ClassNotFound的地方不一致。国外朋友的应用在初始化LoggingEvent对象的时候报错,而我这边的LoggingEvent是正常初始化的。最后还是打算自己去翻一下源码,彻底搞清楚这个问题。3.源码解答为了快速定位问题,直接用方法调用栈走logback的关键方法,很快找到问题所在。答案就在LoggingEvent的构造方法上,如下图:只有lc.isPackagingDataEnabled()为true,才会调用calculatePackagingData()方法,那么isPackagingDataEnabled()的返回值是多少呢?跟着走,发现这个方法返回的值是LoggerContext的一个成员属性,默认是false,所以肯定是修改了默认配置的地方:简单暴力的方法,直接全局搜索引用packagingDataEnabled的地方,然后发现有一个setPackagingDataEnabled()方法是专门设置的,然后看哪里引用了setPackagingDataEnabled()。还好只有一个地方调用了这个方法:ch.qos.logback.classic.joran.action.ConfigurationAction#begin,部分源码如下:LoggerContextlc=(LoggerContext)context;//是这里容易想到,就是在配置文件中配置newvaluebooleanpackagingData=OptionHelper.toBoolean(ic.subst(attributes.getValue(PACKAGING_DATA_ATTR)),LoggerContext.DEFAULT_PACKAGING_DATA);lc.setPackagingDataEnabled(packagingData);看PACKAGING_DATA_ATTR的值就知道是通过配置文件中的哪个参数影响packagingDataEnabled的默认值。现在知道配置文件中必须要设置packagingDataEnabled为true,但是不知道这个配置是做什么用的,所以直接去官网查了下【官方学习地址】:官网明明说这个参数是在栈信息的基础上,额外加入了jar包的名称和版本信息。并且还明确指出,这个配置参数虽然有用,但是非常昂贵【每个类都会触发一次类加载操作】。4.ClassNotFound的根源至此,我们知道在logback.xml中配置了packagingData="true",导致packagingData相关方法的执行。logback在打印错误信息的时候,一般都会输出线程栈信息,导致每一行栈信息都会触发类加载,但是ClassNotFound是怎么回事呢?其实这里我马上就想到了AOP。首先,客户的日志输出操作写在切面类中,而在Spring中,Spring会为cut方法所在的类重新创建一个代理类Bean。不管是JDK动态代理还是CGLIB动态代理创建的代理类Bean在本地磁盘上都没有对应的class文件,所以在类加载过程中一定找不到这些class文件,就会抛出ClassNotFound。错误。为了验证这个猜想,我尝试在本地打印Pointcut指向的类中的日志,并输出堆栈信息:通过本地压测,成功恢复了客户系统的问题,本地堆栈信息为如下:5.结束折腾了半天,终于遇到一个稍微有点意思的问题,开心的记录下来。重点分析思路,当然对于logback还是提一下:packagingData="true"不要随意配置,性能很差;尝试使用异步日志;注意日志格式配置:%F-java源文件名;%L-java源代码行数;%C——java类名;%M-java方法名,所有这些都会导致输出线程栈信息,消耗CPU资源;日志压缩,注意压缩频率【如果磁盘空间足够就不要压缩】immediateFlush默认为true,如果想要更高的日志吞吐量,设置为false;【应用程序意外退出可能会导致少量日志丢失】