源碼角度了解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;
}
這個方法主要有三個步驟:
- 調用witnessClasses()方法,這個方法傳回的是目前插件版本中特有的類,因為一個開源元件可能有多個釋出版本,它們包含相同的目标類,但由于版本疊代器,它們可能具有相同的名稱,但方法不同,或者方法參數清單不同。這時候就需要這個方法來進行比對了
- 周遊集合,判斷類加載器中是否有對應的版本的特有類,如果有進入下一步,如果沒有就傳回null
- 調用enhance()方法來對目标類增強,enhance()方法是抽象方法,具體實作類是抽象類ClassEnhancePluginDefine
- 最後設定增強完成的辨別,也就是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;
}
- 攔截類靜态方法來進行增強
- 攔截構造函數和類執行個體方法進行增強
攔截類靜态方法
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;
}
- 調用getStaticMethodsInterceptPoints()方法擷取插件的靜态方法的攔截點,這個方法是個抽象類,具體邏輯延遲到AbstractClassEnhancePluginDefine的子類中,這是模闆方法模式的一種展現
- 周遊攔截點,,擷取方法攔截器,如果攔截器為空就抛出異常,根據增強的時候是否需要修改參數,需要修改參數的通過StaticMethodsInterWithOverrideArgs進行攔截,不需要修改參數的通過 StaticMethodsInter
StaticMethodsInterWithOverrideArgs
StaticMethodsInterWithOverrideArgs是byte-buddy 的lanjie器來lanjie類執行個體方法,它提供了 byte-buddy 和 sky-walking 插件之間的橋梁,它的intercept()方法中對目标靜态方法進行增強,具體方法中先加載StaticMethodsAroundInterceptor攔截器,StaticMethodsAroundInterceptor是一個接口,其他插件一般會實作這個接口來自定義攔截方法的邏輯,然後執行攔截器的beforeMethod()方法,beforeMethod()方法可以對參數進行改動,根據beforeMethod()方法的運作結果判斷是否執行真正的方法,然後執行afterMethod()方法,如果抛出異常執行handleMethodException()方法
StaticMethodsInter
總結
❤️ 感謝大家
- 歡迎關注我❤️,點贊👍🏻,評論🤤,轉發🙏動,可以暢所欲言,與大神們一起交流,一起學習。
- 有不當之處歡迎批評指正。