第六章 skywalking agent启动

1,195 阅读2分钟

Java agent启动

前面主要介绍了,java agent,本章主要介绍一下 skywalking的agent启动流程,细节后面章节慢慢介绍。

SkyWalking 采用的是使用静态启动方式。
  • 在类加载时对目标类的字节码可以进行任意修改,只要最后能符合jvm字节码规范,校验通过
  • 入口方法 premain
源码看一下启动类

找到apm-sniffer工程中的apm-agent模块。里面就一个 SkyWalkingAgent类 找到premain()启动入口方法;

public static void premain(String agentArgs, Instrumentation instrumentation) throws PluginException {
    final PluginFinder pluginFinder;
    try {
        //1 
        SnifferConfigInitializer.initializeCoreConfig(agentArgs);
    } catch (Exception e) {
        // try to resolve a new logger, and use the new logger to write the error log here
        LogManager.getLogger(SkyWalkingAgent.class)
                .error(e, "SkyWalking agent initialized failure. Shutting down.");
        return;
    } finally {
        // refresh logger again after initialization finishes
        LOGGER = LogManager.getLogger(SkyWalkingAgent.class);
    }

    try {
        //2 
        pluginFinder = new PluginFinder(new PluginBootstrap().loadPlugins());
    } catch (AgentPackageNotFoundException ape) {
        LOGGER.error(ape, "Locate agent.jar failure. Shutting down.");
        return;
    } catch (Exception e) {
        LOGGER.error(e, "SkyWalking agent initialized failure. Shutting down.");
        return;
    }

    final ByteBuddy byteBuddy = new ByteBuddy().with(TypeValidation.of(Config.Agent.IS_OPEN_DEBUGGING_CLASS));
    //3 
    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()));
    //jdk 加载插件
    JDK9ModuleExporter.EdgeClasses edgeClasses = new JDK9ModuleExporter.EdgeClasses();
    try {
        //4 
        agentBuilder = BootstrapInstrumentBoost.inject(pluginFinder, instrumentation, agentBuilder, edgeClasses);
    } catch (Exception e) {
        LOGGER.error(e, "SkyWalking agent inject bootstrap instrumentation failure. Shutting down.");
        return;
    }

    try {
        //
        agentBuilder = JDK9ModuleExporter.openReadEdge(instrumentation, agentBuilder, edgeClasses);
    } catch (Exception e) {
        LOGGER.error(e, "SkyWalking agent open read edge in JDK 9+ failure. Shutting down.");
        return;
    }

    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.");
        }
    }
    //5 
    agentBuilder.type(pluginFinder.buildMatch())
                // 对字节码处理重写Transformer#transform, 修改字节码,并且根据插件加一层拦截器
                .transform(new Transformer(pluginFinder))
                // 增强静态方法,增强实例方法        主要的方式是拿到对应的插件的具体实现,找到要增强的静态、实例方法名
                .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
                .with(new RedefinitionListener())
                .with(new Listener())
                // 然后判断是否需要进行增强,插入对应的插件实现,然后实现插件的增强逻辑即可
                .installOn(instrumentation);

    try {
        // 6 
        ServiceManager.INSTANCE.boot();
    } catch (Exception e) {
        LOGGER.error(e, "Skywalking agent boot failure.");
    }
    // 7 
    Runtime.getRuntime()
            .addShutdownHook(new Thread(ServiceManager.INSTANCE::shutdown, "skywalking service shutdown thread"));
}

以上是源码主要流程

  • 1 初始化配置,加载所有的配置项
  • 2 查找并解析SkyWalking-plugin.def插件文件;使用java spi 找到插件加载,创建描述文件,并初始化到容器中。
  • 3 设置agent byteBuddy 用于动态创建字节码对象。过滤非必要的包名
  • 4 加载到的所有插件,初始化
  • 5 buildMatch命中的类 判断是否需要动态字节码代理
  • 6 启动服务,监控所有的匹配的插件服务,然后执行prepare、startup、onComplete
  • 7 jvm 关闭钩子

后面会逐步挨个分析里面都做了什么,怎么实现的