SW 通过插件增强Java类
2025/8/4大约 3 分钟
SW 通过插件增强Java类
代码位置: org.apache.skywalking.apm.agent.SkyWalkingAgent.Transformer#transform
在这之前,sw 已经寻找到了所有的插件。
接下来的操作,就是sw要使用这些插件,利用插件增强目标的Java类。
而本次讨论的就是 sw 如何使用 插件增强 目标Java类
1. skyWalking 如何匹配插件
再sky walking 的插件定义中,有这样一个函数:
/**
* Define the {@link ClassMatch} for filtering class.
*
* @return {@link ClassMatch}
*/
protected abstract ClassMatch enhanceClass();
这个函数用于指定插件增强哪个Java类。需要注意的是,这个函数的返回值不是一个 Class 对象,而是一个 ClassMatch 对象。
这个类的功能类似于一个过滤器,用于通过指定的规则,匹配出需要增强的类。
- NameMatch: 通过类名匹配
- PrefixMatch:通过类名前缀匹配
- InterfaceMatch:通过接口匹配
- MultiClassNameMatch:通过多个类名匹配
... 其他的实现方式就不一一列举了
找到合适的插件之后,就会调用插件的enhance
函数,来增强目标类。AbstractClassEnhancePluginDefine#enhance
增强分为两类:
- 增强类实例函数
- 包括构造函数
- 对象函数
- 增强静态函数
1.2 skyWalking 如何增强类实例函数
再上面说到,会调用插件的enhance
函数,来增强目标类。
再enhance函数中,声明了两种方法来增强一个Java类:
enhanceInstance
:增强类实例函数、构造函数enhanceClass
:增强静态函数
两者的增强流程其实大差不差,大致是以下步骤:
- 获取当前插件的拦截点
- 静态函数拦截点
getStaticMethodsInterceptPoints
- 实例函数拦截点
getInstanceMethodsInterceptPoints
- 构造函数拦截点
getConstructorsInterceptPoints
- 遍历拦截点,对每一个拦截点进行增强
1.3 skyWalking 具体如何增强一个Java类
通过告诉byteBuddy的builder 拦截5. 启动sw的服务.md规则,将指定的函数执行,委托给我们组件声明的目标函数去执行。
下面其实就是一段 很正常的byteBuddy代码,用于增强一个Java类的构造函数。
newClassBuilder = newClassBuilder.constructor(constructorInterceptPoint.getConstructorMatcher()) // 拦截构造函数
// 使用默认拦截规则
.intercept(SuperMethodCall.INSTANCE.andThen(MethodDelegation.withDefaultConfiguration()
// 将此函数,委托给谁去执行
.to(new ConstructorInter(constructorInterceptPoint.getConstructorInterceptor(), classLoader), delegateNamingResolver.resolve(constructorInterceptPoint))));
通过上面代码声明,byteBuddy就添加了类的构造函数的拦截规则。
会在实例化一个类的时候,调用ConstructorInter
的intercept
函数,来执行我们的目标函数。
那时候,我们就可以再声明的intercept
函数中,执行我们的目标函数了。进行自定义操作了!!!
拦截对象函数
newClassBuilder = newClassBuilder.method(junction) // 指定函数拦截规则
.intercept(MethodDelegation.withDefaultConfiguration() // 使用默认拦截规则
// 将此函数,委托给谁去执行
.to(new InstMethodsInter(interceptor, classLoader), delegateNamingResolver.resolve(instanceMethodsInterceptPoint)));
拦截静态函数
指定静态函数的拦截,将其委托给我们声明的目标函数去执行。
newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher()))
.intercept(MethodDelegation.withDefaultConfiguration()
.to(new StaticMethodsInter(interceptor), delegateNamingResolver.resolve(staticMethodsInterceptPoint)));