源码角度了解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
StaticMethodsInter的逻辑和StaticMethodsInterWithOverrideArgs类差不多,主要差别在于beforeMethod()不会对参加进行改动。
总结
这篇文章我们讲了Skywalking初始化过程中对插件的加载,切入点是AbstractClassEnhancePluginDefined的define()方法,方法中先获取插件这个版本的特有类,然后增强模板类,增强方法是在ClassEnhancePluginDefine类中实现了,具体是增强静态方法、构造方法和实例方法,拦截静态方法分为两部,第一步获取拦截点,这个过程延迟到AbstractClassEnhancePluginDefine子类中实现,这是模板方法模式的体现,第二步拦截增强,涉及到的两个类StaticMethodsInterWithOverrideArgs和StaticMethodsInter,它们的区别在于StaticMethodsInterWithOverrideArgs的beforeMethod()方法可以对参数进行修改,拦截方法对应的拦截器是StaticMethodsAroundInterceptor的实现类,下篇文章我们将对ClassEnhancePluginDefine的拦截构造方法和类实例方法进行分析。
❤️ 感谢大家
如果你觉得这篇内容对你挺有有帮助的话:
- 欢迎关注我❤️,点赞👍🏻,评论🤤,转发🙏动,可以畅所欲言,与大神们一起交流,一起学习。
- 有不当之处欢迎批评指正。