定制agent实际是在定制ByteBuddy字节码增强规则。
ps:其中参数Config.Agent.IS_OPEN_DEBUGGING_CLASS配置如果为true,会将所有测试类文件保存到/debugging目录下
final ByteBuddy byteBuddy = new ByteBuddy().with(TypeValidation.of(Config.Agent.IS_OPEN_DEBUGGING_CLASS));
创建一个AgentBuilder定制bytebuddy的行为
首先指定了一些忽略的类,例如以net.bytebuddy.、org.slf4j开头的。忽略所有skywalking的工具类,isSynthetic忽略编译器生成的类
AgentBuilder agentBuilder = new AgentBuilder.Default(byteBuddy).ignore(
nameStartsWith("net.bytebuddy.")
.or(nameStartsWith("org.slf4j."))
.or(nameStartsWith("org.groovy."))
.or(nameContains("javassist"))
.or(nameContains(".asm."))
.or(nameContains(".reflectasm."))
.or(nameStartsWith("sun.reflect"))
.or(allSkyWalkingAgentExcludeToolkit())
.or(ElementMatchers.isSynthetic()));
将一些重要的插件及其他类注入到Bootstrap classloader中。其中遵循双亲委派原则,顶层父类无法找到子加载器中加载的类,将这些插件注入到Bootstrap classloader中,方便后续使用。
BootstrapInstrumentBoost.inject(pluginFinder, instrumentation, agentBuilder, edgeClasses);
public static AgentBuilder inject(PluginFinder pluginFinder, Instrumentation instrumentation,
AgentBuilder agentBuilder, JDK9ModuleExporter.EdgeClasses edgeClasses) throws PluginException {
Map<String, byte[]> classesTypeMap = new HashMap<>();
if (!prepareJREInstrumentation(pluginFinder, classesTypeMap)) {
return agentBuilder;
}
if (!prepareJREInstrumentationV2(pluginFinder, classesTypeMap)) {
return agentBuilder;
}
for (String highPriorityClass : HIGH_PRIORITY_CLASSES) {
loadHighPriorityClass(classesTypeMap, highPriorityClass);
}
for (String highPriorityClass : ByteBuddyCoreClasses.CLASSES) {
loadHighPriorityClass(classesTypeMap, highPriorityClass);
}
/**
* Prepare to open edge of necessary classes.
*/
for (String generatedClass : classesTypeMap.keySet()) {
edgeClasses.add(generatedClass);
}
ClassInjector.UsingUnsafe.Factory factory = ClassInjector.UsingUnsafe.Factory.resolve(instrumentation);
factory.make(null, null).injectRaw(classesTypeMap);
agentBuilder = agentBuilder.with(new AgentBuilder.InjectionStrategy.UsingUnsafe.OfFactory(factory));
return agentBuilder;
}
根据配置,判断是否允许将skywalking增强类进行保存,允许其他agent进行增强
if (Config.Agent.IS_CACHE_ENHANCED_CLASS) {
try {
agentBuilder = agentBuilder.with(new CacheableTransformerDecorator(Config.Agent.CLASS_CACHE_MODE));
LOGGER.info("SkyWalking agent class cache [{}] activated.", Config.Agent.CLASS_CACHE_MODE);
} catch (Exception e) {
LOGGER.error(e, "SkyWalking agent can't active class cache.");
}
}
agentBuilder.type(pluginFinder.buildMatch()) //指定需要拦截的类
.transform(new Transformer(pluginFinder)) //指定拦截操作类,具体实际操作的类中transform方法
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION) //RETRANSFORMATION和REDEFINITION是否保留修改前的方法
.with(new RedefinitionListener())
.with(new Listener()) //注册监听器
.installOn(instrumentation); //将agent安装到instrumentation
RETRANSFORMATION在修改方法后,保留原方法,例如
class Person{
void say(){
sout(“hello”);
}
}
经过bytebuddy增强,对方法进行了重定义,复制了一个原方法,进行了重写。同时保留了原方法。
class Person{
void say(){
sout(“hi”);
}
void say$001(){
sout(“hi”);
}
}。
而REDEFINITION直接就是替换原方法。
总结:
- 创建bytebuddy实例
- 指定bytebuddy要忽略的类
- 将必要的类注入到BootstrapClassLoader中
- 解决JDK模块系统的跨模块访问
- 根绝配置决定是否将字节码保存到磁盘、内存中
- 细节定制:
1.指定Bytebuddy要拦截的类
2.指定字节码增强的类
3.指定字节增强的模式
4.注册监听器
5.将agent安装到instrumentation