天天看點

源碼角度了解Skywalking之AbstractClassEnhancePluginDefine插件增強定義源碼角度了解Skywalking之AbstractClassEnhancePluginDefine插件增強定義

源碼角度了解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

總結

❤️ 感謝大家

  1. 歡迎關注我❤️,點贊👍🏻,評論🤤,轉發🙏動,可以暢所欲言,與大神們一起交流,一起學習。
  2. 有不當之處歡迎批評指正。