接上篇:
对于所有的skywalking-plugin.def配置文件中定义的agent插件,将通过如下代码生效匹配规则和拦截逻辑。
agentBuilder
.type(pluginFinder.buildMatch())//匹配规则:待增强的类
.transform(new Transformer(pluginFinder))//根据匹配规则和增强逻辑创建Transformer:
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
.with(new Listener())//回调接口,用来在debug模式下保存增强后的字节码文件
.installOn(instrumentation);
1.pluginFinder.buildMatch():匹配规则
//直接根据类名称匹配的插件
private final Map<String, LinkedList<AbstractClassEnhancePluginDefine>> nameMatchDefine = new HashMap<String, LinkedList<AbstractClassEnhancePluginDefine>>();
//非名称匹配:方法注解匹配、类注解匹配等
private final List<AbstractClassEnhancePluginDefine> signatureMatchDefine = new ArrayList<AbstractClassEnhancePluginDefine>();
//返回bytebuddy元素匹配器,用户判断是否匹配
public ElementMatcher<? super TypeDescription> buildMatch() {
ElementMatcher.Junction judge = new AbstractJunction<NamedElement>() {
@Override
public boolean matches(NamedElement target) {
//直接根据类名称匹配
return nameMatchDefine.containsKey(target.getActualName());
}
};
judge = judge.and(not(isInterface()));
for (AbstractClassEnhancePluginDefine define : signatureMatchDefine) {
ClassMatch match = define.enhanceClass();
if (match instanceof IndirectMatch) {
//其他规则匹配
judge = judge.or(((IndirectMatch)match).buildJunction());
}
}
return new ProtectiveShieldMatcher(judge);
}
增强类匹配规则需要实现ClassMatch接口,skywalking中预定义了一些常用匹配规则
ER图如下:
image.png
NameMatch:直接根据类名称匹配
ClassAnnotationMatch:类注解匹配
MethodAnnotationMatch:方法注解匹配
HierarchyMatch:父类或父接口匹配
MultiClassNameMatch:直接根据类名称匹配(类名称数组、逻辑关系--或)
2.new Transformer(pluginFinder):根据匹配规则和增强逻辑创建AgentBuilder.Transformer
private static class Transformer implements AgentBuilder.Transformer {
private PluginFinder pluginFinder;
Transformer(PluginFinder pluginFinder) {
this.pluginFinder = pluginFinder;
}
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module) {
//当前类typeDescription对应的插件集合
List<AbstractClassEnhancePluginDefine> pluginDefines = pluginFinder.find(typeDescription);
if (pluginDefines.size() > 0) {
DynamicType.Builder<?> newBuilder = builder;
EnhanceContext context = new EnhanceContext();
for (AbstractClassEnhancePluginDefine define : pluginDefines) {
//插件对应的增强逻辑
DynamicType.Builder<?> possibleNewBuilder = define.define(typeDescription, newBuilder, classLoader, context);
if (possibleNewBuilder != null) {
newBuilder = possibleNewBuilder;
}
}
if (context.isEnhanced()) {
logger.debug("Finish the prepare stage for {}.", typeDescription.getName());
}
return newBuilder;
}
return builder;
}
}
此处需要重点解释的是如何基于skywaling插件定义的增强逻辑构建bytebuddy的DynamicType.Builder(动态类型构造器)
回顾上篇的插件定义ER图:
image.png
依次次通过如下函数链构建DynamicType.Builder
AbstractClassEnhancePluginDefine.define => ClassEnhancePluginDefine.enhance
=>ClassEnhancePluginDefine.enhanceClass=>ClassEnhancePluginDefine.enhanceInstance
@Override
protected DynamicType.Builder<?> enhance(TypeDescription typeDescription,
DynamicType.Builder<?> newClassBuilder, ClassLoader classLoader,
EnhanceContext context) throws PluginException {
//根据getStaticMethodsInterceptPoints(待增强的静态方法和拦截处理器)
//在DynamicType.Builder构建中嵌入增强逻辑
newClassBuilder = this.enhanceClass(typeDescription, newClassBuilder, classLoader);
//根据getConstructorsInterceptPoints(待增强的构造方法和拦截处理器)
//根据getInstanceMethodsInterceptPoints(待增强的实例方法和拦截处理器)
//在DynamicType.Builder构建中嵌入增强逻辑
newClassBuilder = this.enhanceInstance(typeDescription, newClassBuilder, classLoader, context);
return newClassBuilder;
}
以静态方法增强逻辑嵌入为例子:
StaticMethodsInterceptPoint[] staticMethodsInterceptPoints = getStaticMethodsInterceptPoints();
for (StaticMethodsInterceptPoint staticMethodsInterceptPoint : staticMethodsInterceptPoints) {
String interceptor = staticMethodsInterceptPoint.getMethodsInterceptor();
newClassBuilder =
//指定方法匹配规则
newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher()))
.intercept(
MethodDelegation.withDefaultConfiguration()
.withBinders(
Morph.Binder.install(OverrideCallable.class)
)
//拦截处理器
.to(new StaticMethodsInterWithOverrideArgs(interceptor))
);
3.new Listener() 回调接口,用来在debug模式下保存增强后的字节码文件
实现bytebuddy的AgentBuilder.Listener接口,基于事件回调
private static class Listener implements AgentBuilder.Listener {
@Override
public void onDiscovery(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded) {
}
@Override
public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module,
boolean loaded, DynamicType dynamicType) {
if (logger.isDebugEnable()) {
logger.debug("On Transformation class {}.", typeDescription.getName());
}
//在debug模式下保存增强后的字节码文件
InstrumentDebuggingClass.INSTANCE.log(dynamicType);
}
@Override
public void onIgnored(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module,
boolean loaded) {
}
@Override
public void onError(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded,
Throwable throwable) {
logger.error("Enhance class " + typeName + " error.", throwable);
}
@Override
public void onComplete(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded) {
}
}
网友评论