日志JavaAgent-NoClassDefFoundError

一、引言

        组内最近做了一个日志公共组件,用的是javaagent的方式,之前搞的maven jar包每次都要把所有系统都发一遍,太麻烦。

        javaagent通过Java虚拟机(JVM)的Instrumentation API来实现代码的侵入。通过Instrumentation API,Java agent可以在类加载过程中修改字节码,向目标代码中插入自定义的逻辑或进行其他操作。我们的组件使用bytebuddy进行字节码修改。

日志JavaAgent-NoClassDefFoundError_第1张图片

        今天发布系统会在流水线把这个日志组件带进去,然后就出现了SoaServiceLogAction java.lang.NoClassDefFoundError: Could not initialize class **.LogConfig。

二、分析

1、原因

        这个报错是很模糊的,根本不知道具体原因,正常有以下几种原因:

1. 缺少依赖:如果类 `**.LogConfig` 依赖于其他类或库,而这些依赖没有正确地被引入到项目中,就会导致找不到类的定义。

2. 类初始化失败:如果类的静态初始化块或静态字段初始化过程中发生异常,就会导致类初始化失败。这可能是因为初始化过程中的代码抛出了异常,或者依赖的资源无法访问或加载。

3. 类路径冲突:如果类 `**.LogConfig`在多个地方存在,可能会导致类路径冲突,从而无法正确加载类的定义。

2、组件

        还是要看下代码,这里只列出了出问题的地方,省略了排查其他代码的过程。

public class LogConfig {
private static Map config = Config.get("**.properties").asMap();
public static String scenario() {
        return config.get(LOG_SCENARIO);
    }
}

        这个没有类没有被正确初始化才导致了NoClassDefFoundError,这个类在什么时候被调用呢?

3、JavaAgent

@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
    public static void OnMethodExit(
        @Advice.AllArguments(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object[] allArguments,
        @Advice.Thrown Throwable throwable) {
        try {
            if (StringUtils.isBlank(LogConfig.scenario())) {
            return;
        }
            //日志处理
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

        `@Advice.OnMethodExit` 是bytebuddy库中的一个注解,用于在方法退出时进行拦截和处理。它可以被用于在方法执行完毕后执行一些特定的逻辑,例如记录日志、统计方法执行时间等。

        这里可以看到判断一下对应的场景有没有配置使用日志组件。场景很多,有数据库、链路调用、mq等等,方便针对性的记录日志。

4、初始化分析

        LogConfig在每次调用或者操作DB的时候都会被调用其中的静态方法scenario,这时候就应该被初始化,说明这个方法有问题。因为静态方法属于类级别的方法,调用静态方法会导致类的初始化。在初始化过程中,会执行静态初始化块和静态字段的初始化操作。因此,在调用 `scenario()` 方法之前,类 `LogConfig` 的静态字段 `config` 会被初始化。

        那么会有什么问题呢?config字段也就是加载一下配置而已。如果配置不存在呢?作者想到这里看了一下配置中心,果然没有这个文件。

三、解决

        作者联系了系统对应的负责人加上**.properties这个文件,但是感觉组件应该在本地建一个文件,如果加载不到配置中心的也能加载到本地的。不然推广到其他部门的时候就会产生这种乌龙。

四、总结

        java agent做公共代码的抽离是个好方式,但是就像作者上次Log4j-tag丢失-CSDN博客发现的问题一样,不看组件源代码根本不知道发生了什么。也就要求研发人员对JavaAgent有一定的了解。

        下一期作者准备讲讲搭建和使用JavaAgent,有兴趣的同学点点关注。

你可能感兴趣的:(java,开发语言)