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 关闭钩子
后面会逐步挨个分析里面都做了什么,怎么实现的