2

起因

偶然一次路过同事电脑,看着黑底蓝色满屏的堆栈信息,过去笑着拍了拍他的肩膀说道「小哥,又在写BUG呢」凑过去仔细看了一眼异常堆栈详情,「虎躯一震」哟,高端的,这堆栈后面的还有类的包路径信息呢呢,以前看堆栈的时候咋没有特别注意

坐下打开电脑翻看了下一下Logback的代码核心计算逻辑ch.qos.logback.classic.spi.PackagingDataCalculator

clipboard.png
获取Package下的MANIFEST.MF文件里面Implementation-Version信息

clipboard.png
和获取类所在的jar包路径
可以看到所有的信息都在类对应的Class对象上

深入思考

很多时候为了解决Maven扁平化依赖臃肿和依赖冲突问题,我们往往会用上类隔离框架,比如说支付宝开源的sofa-ark,其基本原理就是使用单独的ClassLoader加载,并且将一部门类EXPORT,假设如果遇到没有被EXPORT出来的类(幽灵Class),会发生什么情况呢?

分析

因为是属于没有被EXPORT出来的类所以最终会委托给应用类加载器加载

clipboard.png

clipboard.png
为了防止重复加载,所以应用类加载器在加载类的时候会根据加载的className加锁,因为类也不是应用类加载器加载的所以会进行双亲委派加载,最后抛出ClassNotFoundException,再结合PackagingDataCalculator对异常的处理
clipboard.png程序不会终止,所以我们可以得出结论只要碰到「幽灵Class」logback都会重新把类按照双亲委派的方式加载一遍。
有锁的地方就会有锁竞争,并且Class.load也是一个耗时的过程,所以同一个ClassName如果并发出现在日志堆栈中势必会导致一部分线程会block,这对于线上系统中简直就是灾难.

改进

在最近的logback版本中并没有发现对ClassNotFoundException的类做特殊处理,并且正如logback官方说的

While useful, packaging data is expensive to compute, especially in applications with frequent exceptions.

所以只要logback的版本大于1.1.3,packageDate这个配置默认都是关闭的
https://logback.qos.ch/manual...


iMouseWu
1.6k 声望53 粉丝

Conding with Java