接上篇:
對(duì)于所有的skywalking-plugin.def配置文件中定義的agent插件,將通過(guò)如下代碼生效匹配規(guī)則和攔截邏輯。
agentBuilder
.type(pluginFinder.buildMatch())//匹配規(guī)則:待增強(qiáng)的類
.transform(new Transformer(pluginFinder))//根據(jù)匹配規(guī)則和增強(qiáng)邏輯創(chuàng)建Transformer:
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
.with(new Listener())//回調(diào)接口,用來(lái)在debug模式下保存增強(qiáng)后的字節(jié)碼文件
.installOn(instrumentation);
1.pluginFinder.buildMatch():匹配規(guī)則
//直接根據(jù)類名稱匹配的插件
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) {
//直接根據(jù)類名稱匹配
return nameMatchDefine.containsKey(target.getActualName());
}
};
judge = judge.and(not(isInterface()));
for (AbstractClassEnhancePluginDefine define : signatureMatchDefine) {
ClassMatch match = define.enhanceClass();
if (match instanceof IndirectMatch) {
//其他規(guī)則匹配
judge = judge.or(((IndirectMatch)match).buildJunction());
}
}
return new ProtectiveShieldMatcher(judge);
}
增強(qiáng)類匹配規(guī)則需要實(shí)現(xiàn)ClassMatch接口唤蔗,skywalking中預(yù)定義了一些常用匹配規(guī)則
ER圖如下:
NameMatch:直接根據(jù)類名稱匹配
ClassAnnotationMatch:類注解匹配
MethodAnnotationMatch:方法注解匹配
HierarchyMatch:父類或父接口匹配
MultiClassNameMatch:直接根據(jù)類名稱匹配(類名稱數(shù)組义锥、邏輯關(guān)系--或)
2.new Transformer(pluginFinder):根據(jù)匹配規(guī)則和增強(qiáng)邏輯創(chuàng)建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) {
//當(dāng)前類typeDescription對(duì)應(yīng)的插件集合
List<AbstractClassEnhancePluginDefine> pluginDefines = pluginFinder.find(typeDescription);
if (pluginDefines.size() > 0) {
DynamicType.Builder<?> newBuilder = builder;
EnhanceContext context = new EnhanceContext();
for (AbstractClassEnhancePluginDefine define : pluginDefines) {
//插件對(duì)應(yīng)的增強(qiáng)邏輯
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;
}
}
此處需要重點(diǎn)解釋的是如何基于skywaling插件定義的增強(qiáng)邏輯構(gòu)建bytebuddy的DynamicType.Builder(動(dòng)態(tài)類型構(gòu)造器)
回顧上篇的插件定義ER圖:
依次次通過(guò)如下函數(shù)鏈構(gòu)建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 {
//根據(jù)getStaticMethodsInterceptPoints(待增強(qiáng)的靜態(tài)方法和攔截處理器)
//在DynamicType.Builder構(gòu)建中嵌入增強(qiáng)邏輯
newClassBuilder = this.enhanceClass(typeDescription, newClassBuilder, classLoader);
//根據(jù)getConstructorsInterceptPoints(待增強(qiáng)的構(gòu)造方法和攔截處理器)
//根據(jù)getInstanceMethodsInterceptPoints(待增強(qiáng)的實(shí)例方法和攔截處理器)
//在DynamicType.Builder構(gòu)建中嵌入增強(qiáng)邏輯
newClassBuilder = this.enhanceInstance(typeDescription, newClassBuilder, classLoader, context);
return newClassBuilder;
}
以靜態(tài)方法增強(qiáng)邏輯嵌入為例子:
StaticMethodsInterceptPoint[] staticMethodsInterceptPoints = getStaticMethodsInterceptPoints();
for (StaticMethodsInterceptPoint staticMethodsInterceptPoint : staticMethodsInterceptPoints) {
String interceptor = staticMethodsInterceptPoint.getMethodsInterceptor();
newClassBuilder =
//指定方法匹配規(guī)則
newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher()))
.intercept(
MethodDelegation.withDefaultConfiguration()
.withBinders(
Morph.Binder.install(OverrideCallable.class)
)
//攔截處理器
.to(new StaticMethodsInterWithOverrideArgs(interceptor))
);
3.new Listener() 回調(diào)接口柳沙,用來(lái)在debug模式下保存增強(qiáng)后的字節(jié)碼文件
實(shí)現(xiàn)bytebuddy的AgentBuilder.Listener接口,基于事件回調(diào)
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模式下保存增強(qiáng)后的字節(jié)碼文件
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) {
}
}