skywalking~定制agent

定制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 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直接就是替换原方法。

总结:
  1. 创建bytebuddy实例
  2. 指定bytebuddy要忽略的类
  3. 将必要的类注入到BootstrapClassLoader中
  4. 解决JDK模块系统的跨模块访问
  5. 根绝配置决定是否将字节码保存到磁盘、内存中
  6. 细节定制:
    1.指定Bytebuddy要拦截的类
    2.指定字节码增强的类
    3.指定字节增强的模式
    4.注册监听器
    5.将agent安装到instrumentation

你可能感兴趣的:(skywalking,java,skywalking,java,开发语言)