Agent源码解析
入口类
在 apm-sniffer/apm-agent 包下:com.ccb.aicloud.apm.agent.ApmAgent#premain
1 | public static void premain(String agentArgs, Instrumentation instrumentation) throws PluginException { |
- agentArgs: 是 premain 函数得到的程序参数,随同 “– javaagent”一起传入
- instrumentation: 是一个 java.lang.instrument.Instrumentation 的实例,由 JVM 自动传入
利用了javaagent实现了虚拟机级别的aop,利用字节码工具bytebuddy实现字节码增强
初始化
读取配置文件信息,环境变量信息,vm option参数SnifferConfigInitializer.initializeCoreConfig(agentArgs);
加载插件
通过插件加载机制,实现对不同中间件等的监控,即加载对应的插件即可pluginFinder = new PluginFinder(new PluginBootstrap().loadPlugins());
在PluginBootstrap类中的loadPlugins()中:
1 | //先声明一个资源加载器resolver,在resolver中的getResources()会查找skywalking-plugin.def文件中定义的类 |
将返回的plugins传给pluginFinder类,作为构造参数,pluginFinder类中有方法buildMatch()来判断需要修改哪些类的字节码(因为不是每一个类都需要增强):
1 |
|
以dubbo插件为例:
1 | //间接继承了基类 |
通过bytebuddy中的agentBuilder来生成一个agent,并执行相关逻辑
利用bytebuddy的API生成一个代理,并执行transform方法和监听器Listener(主要是日志相关)。
在premain中,通过链式调用,被builderMatch()匹配到的类都会执行transform方法,transform定义了字节码增强的逻辑:
1 | agentBuilder.type(pluginFinder.buildMatch()) |
1 | private static class Transformer implements AgentBuilder.Transformer { |
需要补充的是:AbstractClassEnhancePluginDefine
做为所有的插件都要继承实现的基础, 抽象类AbstractClassEnhancePluginDefine
具体定义了什么行为,这些行为又有哪些意义?什么地方在调用这个方法?AbstractClassEnhancePluginDefine
中有四个方法
enhance
抽象方法, 抽象类中无实现, 子类去实现,具体的增强的逻辑enhanceClass
抽象方法, 抽象类中无实现,子类去实现,具体的要增强的类的 MatchwitnessClasses
也是可以被重载的一个方法,子类可重载define
实例方法,它主要做了下面的几次事 ( 入口方法)- 找到增强插件类的所有显式指定的
WitnessClasses
- 用户自己重载显式指定 - 调用
enhance
方法, 执行真正的插件的增强逻辑,返回新的DynamicType.Builder
- 设置上下文, 标记初始化定义步骤已完成
- 最后再返回新的 第 2 中的增强后的
newClassBuilder
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67public abstract class AbstractClassEnhancePluginDefine {
private static final ILog LOGGER = LogManager.getLogger(AbstractClassEnhancePluginDefine.class);
public DynamicType.Builder<?> define(TypeDescription typeDescription, DynamicType.Builder<?> builder,
ClassLoader classLoader, EnhanceContext context) throws PluginException {
String interceptorDefineClassName = this.getClass().getName();
String transformClassName = typeDescription.getTypeName();
if (StringUtil.isEmpty(transformClassName)) {
LOGGER.warn("classname of being intercepted is not defined by {}.", interceptorDefineClassName);
return null;
}
LOGGER.debug("prepare to enhance class {} by {}.", transformClassName, interceptorDefineClassName);
WitnessFinder finder = WitnessFinder.INSTANCE;
/**
* find witness classes for enhance class
*/
String[] witnessClasses = witnessClasses();
if (witnessClasses != null) {
for (String witnessClass : witnessClasses) {
if (!finder.exist(witnessClass, classLoader)) {
LOGGER.warn("enhance class {} by plugin {} is not working. Because witness class {} is not existed.", transformClassName, interceptorDefineClassName, witnessClass);
return null;
}
}
}
List<WitnessMethod> witnessMethods = witnessMethods();
if (!CollectionUtil.isEmpty(witnessMethods)) {
for (WitnessMethod witnessMethod : witnessMethods) {
if (!finder.exist(witnessMethod, classLoader)) {
LOGGER.warn("enhance class {} by plugin {} is not working. Because witness method {} is not existed.", transformClassName, interceptorDefineClassName, witnessMethod);
return null;
}
}
}
/**
* find origin class source code for interceptor
*/
DynamicType.Builder<?> newClassBuilder = this.enhance(typeDescription, builder, classLoader, context);
context.initializationStageCompleted();
LOGGER.debug("enhance class {} by {} completely.", transformClassName, interceptorDefineClassName);
return newClassBuilder;
}
protected abstract DynamicType.Builder<?> enhance(TypeDescription typeDescription,
DynamicType.Builder<?> newClassBuilder, ClassLoader classLoader, EnhanceContext context) throws PluginException;
protected abstract ClassMatch enhanceClass();
protected String[] witnessClasses() {
return new String[] {};
}
protected List<WitnessMethod> witnessMethods() {
return null;
}
public boolean isBootstrapInstrumentation() {
return false;
}
public abstract ConstructorInterceptPoint[] getConstructorsInterceptPoints();
public abstract InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints();
public abstract StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints();
}
- 找到增强插件类的所有显式指定的
- *这个抽象基类中,最为重要的一个方法 define(),被premain中的transform调用,从而实现插件中的拦截逻辑。**
启动服务
采用插件架构,为了规范所有插件,插件都必须实现BootService这个接口,如下:
1 | //BootService中声明的生命周期方法,agent-core内核会在适当的时机调用不同的生命周期方法 |
在premain方法的最后,会boot启动服务:
1 | try { |
boot类是ServiceManager类下的方法,打开boot方法:
1 | public void boot() { |
- 首先是loadAllService方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43private Map<Class, BootService> loadAllServices() {
Map<Class, BootService> bootedServices = new LinkedHashMap<>();
List<BootService> allServices = new LinkedList<>();
load(allServices);
for (final BootService bootService : allServices) {
Class<? extends BootService> bootServiceClass = bootService.getClass();
boolean isDefaultImplementor = bootServiceClass.isAnnotationPresent(DefaultImplementor.class);
if (isDefaultImplementor) {
if (!bootedServices.containsKey(bootServiceClass)) {
bootedServices.put(bootServiceClass, bootService);
} else {
//ignore the default service
}
} else {
//服务是否有注解@OverrideImplementor,覆盖实现
OverrideImplementor overrideImplementor = bootServiceClass.getAnnotation(OverrideImplementor.class);
if (overrideImplementor == null) {
if (!bootedServices.containsKey(bootServiceClass)) {
bootedServices.put(bootServiceClass, bootService);
} else {
throw new ServiceConflictException("Duplicate service define for :" + bootServiceClass);
}
} else {
Class<? extends BootService> targetService = overrideImplementor.value();
if (bootedServices.containsKey(targetService)) {
boolean presentDefault = bootedServices.get(targetService)
.getClass()
.isAnnotationPresent(DefaultImplementor.class);
if (presentDefault) {
bootedServices.put(targetService, bootService);
} else {
throw new ServiceConflictException(
"Service " + bootServiceClass + " overrides conflict, " + "exist more than one service want to override :" + targetService);
}
} else {
bootedServices.put(targetService, bootService);
}
}
}
}
return bootedServices;
}1
2
3
4
5void load(List<BootService> allServices) {
for (final BootService bootService : ServiceLoader.load(BootService.class, AgentClassLoader.getDefault())) {
allServices.add(bootService);
}
}
** 扩展:Java SPI思想梳理 **
最后一步 注册关闭钩子
设置一个关闭钩子,在JVM关闭时,建立一个线程,调用ServiceManager中的shutdown方法,进行资源释放等。
1 | Runtime.getRuntime() |
扫描二维码,分享此文章