首页 > 编程语言 >源码角度了解Skywalking之AbstractClassEnhancePluginDefine插件增强定义

源码角度了解Skywalking之AbstractClassEnhancePluginDefine插件增强定义

时间:2022-10-03 21:04:36浏览次数:67  
标签:插件 newClassBuilder AbstractClassEnhancePluginDefine 增强 源码 enhance 拦截 方法

源码角度了解Skywalking之AbstractClassEnhancePluginDefine插件增强定义

AbstractClassEnhancePluginDefine是所有插件的抽象类,我们在分析Skywalking初始化流程的时候见到过这个类,初始化的时候将所有的插件进行加载匹配后,在Transformer 的transform()方法中遍历AbstractClassEnhancePluginDefine插件集合,依次调用它的define()方法

AbstractClassEnhancePluginDefined的define()方法

AbstractClassEnhancePluginDefined的define()方法:

public DynamicType.Builder<?> define(TypeDescription typeDescription,
                                         DynamicType.Builder<?> builder, ClassLoader classLoader, EnhanceContext context) throws PluginException {
       ...
        
        String[] witnessClasses = witnessClasses();
        if (witnessClasses != null) {
            for (String witnessClass : witnessClasses) {
                if (!WitnessClassFinder.INSTANCE.exist(witnessClass, classLoader)) {
                    logger.warn("enhance class {} by plugin {} is not working. Because witness class {} is not existed.", transformClassName, interceptorDefineClassName,
                        witnessClass);
                    return null;
                }
            }
        }

        DynamicType.Builder<?> newClassBuilder = this.enhance(typeDescription, builder, classLoader, context);

        context.initializationStageCompleted();
        logger.debug("enhance class {} by {} completely.", transformClassName, interceptorDefineClassName);

        return newClassBuilder;
    }

这个方法主要有三个步骤:

  1. 调用witnessClasses()方法,这个方法返回的是当前插件版本中特有的类,因为一个开源组件可能有多个发布版本,它们包含相同的目标类,但由于版本迭代器,它们可能具有相同的名称,但方法不同,或者方法参数列表不同。这时候就需要这个方法来进行匹配了
  2. 遍历集合,判断类加载器中是否有对应的版本的特有类,如果有进入下一步,如果没有就返回null
  3. 调用enhance()方法来对目标类增强,enhance()方法是抽象方法,具体实现类是抽象类ClassEnhancePluginDefine
  4. 最后设置增强完成的标识,也就是EnhanceContext的isEnhanced设置为true

ClassEnhancePluginDefine

这个类控制所有增强操作,包括增强构造函数、实例方法和静态方法。所有增强都基于三种类型的拦截器点: ConstructorInterceptPoint类、InstanceMethodsInterceptPoint类 和 StaticMethodsInterceptPoint类

我们看一下ClassEnhancePluginDefine的enhance()方法:

protected DynamicType.Builder<?> enhance(TypeDescription typeDescription,
        DynamicType.Builder<?> newClassBuilder, ClassLoader classLoader,
        EnhanceContext context) throws PluginException {
        newClassBuilder = this.enhanceClass(typeDescription, newClassBuilder, classLoader);

        newClassBuilder = this.enhanceInstance(typeDescription, newClassBuilder, classLoader, context);

        return newClassBuilder;
    }
  1. 拦截类静态方法来进行增强
  2. 拦截构造函数和类实例方法进行增强

拦截类静态方法

ClassEnhancePluginDefine的enhanceClass()方法:

private DynamicType.Builder<?> enhanceClass(TypeDescription typeDescription,
        DynamicType.Builder<?> newClassBuilder, ClassLoader classLoader) throws PluginException {
        StaticMethodsInterceptPoint[] staticMethodsInterceptPoints = getStaticMethodsInterceptPoints();
        String enhanceOriginClassName = typeDescription.getTypeName();
        if (staticMethodsInterceptPoints == null || staticMethodsInterceptPoints.length == 0) {
            return newClassBuilder;
        }

        for (StaticMethodsInterceptPoint staticMethodsInterceptPoint : staticMethodsInterceptPoints) {
            String interceptor = staticMethodsInterceptPoint.getMethodsInterceptor();
            if (StringUtil.isEmpty(interceptor)) {
                throw new EnhanceException("no StaticMethodsAroundInterceptor define to enhance class " + enhanceOriginClassName);
            }

            if (staticMethodsInterceptPoint.isOverrideArgs()) {
                if (isBootstrapInstrumentation()) {
                    newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher()))
                        .intercept(
                            MethodDelegation.withDefaultConfiguration()
                                .withBinders(
                                    Morph.Binder.install(OverrideCallable.class)
                                )
                                .to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor))
                        );
                } else {
                    newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher()))
                        .intercept(
                            MethodDelegation.withDefaultConfiguration()
                                .withBinders(
                                    Morph.Binder.install(OverrideCallable.class)
                                )
                                .to(new StaticMethodsInterWithOverrideArgs(interceptor))
                        );
                }
            } else {
                if (isBootstrapInstrumentation()) {
                    newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher()))
                        .intercept(
                            MethodDelegation.withDefaultConfiguration()
                                .to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor))
                        );
                } else {
                    newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher()))
                        .intercept(
                            MethodDelegation.withDefaultConfiguration()
                                .to(new StaticMethodsInter(interceptor))
                        );
                }
            }

        }

        return newClassBuilder;
    }
  1. 调用getStaticMethodsInterceptPoints()方法获取插件的静态方法的拦截点,这个方法是个抽象类,具体逻辑延迟到AbstractClassEnhancePluginDefine的子类中,这是模板方法模式的一种体现
  2. 遍历拦截点,,获取方法拦截器,如果拦截器为空就抛出异常,根据增强的时候是否需要修改参数,需要修改参数的通过StaticMethodsInterWithOverrideArgs进行拦截,不需要修改参数的通过 StaticMethodsInter

StaticMethodsInterWithOverrideArgs

StaticMethodsInterWithOverrideArgs是byte-buddy 的lanjie器来lanjie类实例方法,它提供了 byte-buddy 和 sky-walking 插件之间的桥梁,它的intercept()方法中对目标静态方法进行增强,具体方法中先加载StaticMethodsAroundInterceptor拦截器,StaticMethodsAroundInterceptor是一个接口,其他插件一般会实现这个接口来自定义拦截方法的逻辑,然后执行拦截器的beforeMethod()方法,beforeMethod()方法可以对参数进行改动,根据beforeMethod()方法的运行结果判断是否执行真正的方法,然后执行afterMethod()方法,如果抛出异常执行handleMethodException()方法

StaticMethodsInter

StaticMethodsInter的逻辑和StaticMethodsInterWithOverrideArgs类差不多,主要差别在于beforeMethod()不会对参加进行改动。

总结

这篇文章我们讲了Skywalking初始化过程中对插件的加载,切入点是AbstractClassEnhancePluginDefined的define()方法,方法中先获取插件这个版本的特有类,然后增强模板类,增强方法是在ClassEnhancePluginDefine类中实现了,具体是增强静态方法、构造方法和实例方法,拦截静态方法分为两部,第一步获取拦截点,这个过程延迟到AbstractClassEnhancePluginDefine子类中实现,这是模板方法模式的体现,第二步拦截增强,涉及到的两个类StaticMethodsInterWithOverrideArgs和StaticMethodsInter,它们的区别在于StaticMethodsInterWithOverrideArgs的beforeMethod()方法可以对参数进行修改,拦截方法对应的拦截器是StaticMethodsAroundInterceptor的实现类,下篇文章我们将对ClassEnhancePluginDefine的拦截构造方法和类实例方法进行分析。

❤️ 感谢大家

如果你觉得这篇内容对你挺有有帮助的话:

  1. 欢迎关注我❤️,点赞

    标签:插件,newClassBuilder,AbstractClassEnhancePluginDefine,增强,源码,enhance,拦截,方法
    From: https://blog.51cto.com/u_15460453/5730449

相关文章