前言
Java Agent包含一些后台任务,例如
- 采集JVM参数
- 将span发送到OAP服务器
- 等等
本身Java-Agent是一个自动化埋点的探针程序,它是如何启动自己的后台任务的呢?
如何启动后台任务
首先Java-Agent项目作为一个自动埋点的项目,程序的入口肯定是Instrumentation机制的permain方法:
因此从permain方法入手:查看permain方法的实现,除了修改class实现外,还可以观察到:
很明显,这就是启动后台服务的语句。其中ServiceManager是一个枚举类,接着我们直接查看boot函数的实现:
public enum ServiceManager {
// 省略一些代码...
private Map<Class, BootService> bootedServices = Collections.emptyMap();
public void boot() {
bootedServices = loadAllServices();
prepare();
startup();
onComplete();
}
}
public interface BootService {
void prepare() throws Throwable;
void boot() throws Throwable;
void onComplete() throws Throwable;
void shutdown() throws Throwable;
default int priority() {
return 0;
}
}
boot函数首先加载所有的服务到私有属性bootedServices中。然后调用prepare做前置操作,然后启动所有服务,最后调用完毕勾子。而BootService是一个接口,明显采用模板的设计模式。
接着具体看看loadAllServices函数的实现:
private Map<Class, BootService> loadAllServices() {
Map<Class, BootService> bootedServices = new LinkedHashMap<>();
List<BootService> allServices = new LinkedList<>();
load(allServices);
for (final BootService bootService : allServices) {
// 省略一些过滤处理...
}
return bootedServices;
}
void load(List<BootService> allServices) {
// 使用Java的SPI机制,加载所有的BootService实现
for (final BootService bootService : ServiceLoader.load(BootService.class, AgentClassLoader.getDefault())) {
allServices.add(bootService);
}
}
可以看到load函数中使用ServiceLoader来加载所有实现BootService接口的类,那说明这是采用SPI机制加载进来的。那么我们查看meta-info的services目录
该文件列出了一共19个BootService的实现类名,其内容如下:
// 发送Trace信息给OAP服务器的后台任务
org.apache.skywalking.apm.agent.core.remote.TraceSegmentServiceClient
// 实现采样的后台任务
org.apache.skywalking.apm.agent.core.sampling.SamplingService
org.apache.skywalking.apm.agent.core.remote.GRPCChannelManager
// 实现发送JVM状态的后台任务
org.apache.skywalking.apm.agent.core.jvm.JVMMetricsSender
// 实现采集JVM状态的后台任务
org.apache.skywalking.apm.agent.core.jvm.JVMService
org.apache.skywalking.apm.agent.core.remote.ServiceManagementClient
...
总结
1、所有的后台任务都实现了org.apache.skywalking.apm.agent.core.boot.BootService接口,并实现了
- prepare
- boot
- onComplete
- shutdown
四个模板方法,方便服务管理层进行调用和统一管理。
2、另外在permain函数中通过SPI加载所有BootService实现类(均在meta-info中列清单中),然后调用前三个模板方法,启动后台任务。
查找源码的思路
分享下查看源码思路:观察配置文件,有这个参数:(猜测该参数为将Span发送给OAP服务器这类任务所用)
所以在源码中查找这个参数,然后参数的使用地方,发现是一个BootService,那么顺藤摸瓜就可以找到整个后台任务启动的机制了。
\