Skyingwalking 源码解读 agent 篇
文章目录
- Skyingwalking 源码解读 agent 篇
- 一、 Java Agent 技术
- 二、 SkyWalkingAgent
- 三、SnifferConfigInitializer
- 四、PluginBootstrap
- 五、 AgentClassLoader
- 六、PluginResourcesResolver 插件资源查找器
- 七、PluginCfg 插件配置类
- 八、PluginFinder 查询查找器
- 九、BootstrapInstrumentBoost
- 十、ServiceManager
- 十一、 AbstractClassEnhancePluginDefine
- 十二、 WitnessFinder
- 十三、ClassEnhancePluginDefine
- 十四、 ConstructorInter
- 十五、InstMethodsInterWithOverrideArgs
- 十六、 BootstrapInterRuntimeAssist
- 十七、InterceptorInstanceLoader
一、 Java Agent 技术
Java Agent 是 Java 虚拟机提供的一种扩展机制,它可以在 Java 应用程序运行期间动态地修改字节码,以实现一些特殊的功能。
Java Agent 的实现主要依赖于 Java 虚拟机的 Instrumentation API。这个 API 提供了在运行期间修改字节码的功能,也就是说可以通过 Instrumentation API 在应用程序启动前修改字节码,从而实现一些增强功能。Java Agent 就是利用 Instrumentation API 在应用程序启动前修改字节码,使得应用程序能够在运行期间实现一些特殊的功能。
Java Agent 一般有两个主要组成部分:Agent 类和 Agent 应用程序类。Agent 类是一个独立的 Java 类,它实现了 premain() 方法,这个方法在应用程序启动之前被调用。Agent 应用程序类则是需要在应用程序中运行的类,它的字节码可以在 premain() 方法中通过 Instrumentation API 进行修改,以实现增强功能。
Java Agent 的运行方式可以通过命令行参数来指定,具体来说,可以通过在启动命令中添加如下参数来加载 Agent:
-javaagent:/path/to/agent.jar
其中 /path/to/agent.jar 是 Java Agent 所在的 jar 包路径。
Java Agent 的应用场景比较广泛,例如可以用来实现性能监控、代码注入、字节码增强等功能。
二、 SkyWalkingAgent
Skywalking Java Agent 类, 代理主入口
2.1 premain 主入口
主入口方法,使用 byte-buddy 技术增强在插件中定义的所有类
/**
* Main entrance. Use byte-buddy transform to enhance all classes, which define in plugins.
*/
public static void premain(String agentArgs, Instrumentation instrumentation) throws PluginException {
final PluginFinder pluginFinder;
try {
// 初始化配置信息,agentArgs 为 -javaagent: 后的参数, 详情见第三章 3.1 节
SnifferConfigInitializer.initializeCoreConfig(agentArgs);
} catch (Exception e) {
// 因为配置文件有可能修改过 logger ,所以重新加载一次
LogManager.getLogger(SkyWalkingAgent.class)
.error(e, "SkyWalking agent initialized failure. Shutting down.");
return;
} finally {
// 因为配置文件有可能修改过 logger ,所以重新加载一次
LOGGER = LogManager.getLogger(SkyWalkingAgent.class);
}
try {
// 插件加载 PluginBootstrap 详情见 第四章 4.1 节
// PluginFinder 详情见 第八章 8.1 节
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;
}
// 创建 byteBuddy ByteBuddy 详情见 2.2 节
final ByteBuddy byteBuddy = new ByteBuddy().with(TypeValidation.of(Config.Agent.IS_OPEN_DEBUGGING_CLASS));
// agent builder
AgentBuilder agentBuilder = new AgentBuilder.Default(byteBuddy)
// 匹配规则可以帮助我们过滤掉一些不需要增强的类,从而提高转换器的效率。
.ignore(
nameStartsWith("net.bytebuddy.")
.or(nameStartsWith("org.slf4j."))
.or(nameStartsWith("org.groovy."))
// nameContains("javassist")、nameContains(".asm.")、nameContains(".reflectasm.") 等方法表示忽略包含指定字符串的类,如忽略包含 javassist、.asm.、.reflectasm. 的类等。
.or(nameContains("javassist"))
.or(nameContains(".asm."))
.or(nameContains(".reflectasm."))
.or(nameStartsWith("sun.reflect"))
// allSkyWalkingAgentExcludeToolkit() 方法表示忽略一些 SkyWalking 代理工具包的相关类。
.or(allSkyWalkingAgentExcludeToolkit())
// ElementMatchers.isSynthetic() 方法表示忽略 Java 合成类,即由编译器生成的内部类、Lambda 表达式等。
.or(ElementMatchers.isSynthetic()));
// All ByteBuddy core classes required to expose, including open edge for JDK 9+ module, or Bootstrap instrumentation.
// 所有需要暴露出去的 bytebuddy 的核心类,
JDK9ModuleExporter.EdgeClasses edgeClasses = new JDK9ModuleExporter.EdgeClasses();
try {
// 详情见第九章 9.1 节
agentBuilder = BootstrapInstrumentBoost.inject(pluginFinder, instrumentation, agentBuilder, edgeClasses);
} catch (Exception e) {
LOGGER.error(e, "SkyWalking agent inject bootstrap instrumentation failure. Shutting down.");
return;
}
try {
// 保证 JDK9 模块化之后的类都能访问的到
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 true, SkyWalking agent will cache all instrumented classes to memory or disk files (decided by class cache mode), allow other javaagent to enhance those classes that enhanced by SkyWalking agent.
// 如果是 true, 所有的增强的类都会缓存在内存或者磁盘文件中,取决于配置的缓存模式,允许其它的 agent 去增强被 skywalking 所增强的类
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.");
}
}
// 定义所有被增强的类 详情见 第八章 8.3 节
agentBuilder.type(pluginFinder.buildMatch())
// 定义增强实现
.transform(new Transformer(pluginFinder))
// 被增强后的方法重定义模式 见 本章 2.3 节
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
// 监听器
.with(new RedefinitionListener())
// 监听器
.with(new Listener())
.installOn(instrumentation);
try {
// 详情见 第十章 ServiceManager 10.1 节
ServiceManager.INSTANCE.boot();
} catch (Exception e) {
LOGGER.error(e, "Skywalking agent boot failure.");
}
Runtime.getRuntime()
.addShutdownHook(new Thread(ServiceManager.INSTANCE::shutdown, "skywalking service shutdown thread"));
}
2.2 ByteBuddy 扩展
ByteBuddy 是一个用于创建 Java 字节码的库,可以用于生成类的动态代理、运行时修改类、生成字节码以及其它一些类相关的操作。
2.2.1 new ByteBuddy().with()
new ByteBuddy().with 是使用 ByteBuddy 库创建动态代理类时的一个重要方法,它可以配置代理类的一些参数。
下面是一些常用的参数:
NamingStrategy
:用于指定类的命名策略,默认为SuffixingRandom
,即在类名后面添加一段随机字符串。可以通过实现NamingStrategy
接口来指定自定义的命名策略。ClassFileVersion
:用于指定生成的代理类的版本,默认为当前 JVM 的版本。可以通过ClassFileVersion.of(int majorVersion)
来指定其他版本。MethodGraph.Compiler
:用于指定代理类中的方法顺序,默认为DEFAULT
,即按照源代码中的顺序排列。可以通过MethodGraph.Compiler.ForDeclaredMethods
来指定只包括代理类自身声明的方法,并按照它们的依赖关系排序。TypeValidation
:用于指定类型检查策略,默认为ENABLED
,即启用类型检查。可以通过TypeValidation.DISABLED
来禁用类型检查。Implementation.Context
:用于指定实现的上下文,默认为ASM5
,即使用 ASM 5.x 版本。可以通过Implementation.Context.Disabled
来禁用默认的 ASM 实现,并提供自定义的实现。
下面是一个使用 with
方法的示例:
在这个示例中,我们使用了
NamingStrategy.SuffixingRandom
来指定类名的命名策略为在类名后面添加一段随机字符串,使用了TypeValidation.Disabled()
来禁用类型检查。然后我们使用subclass
方法来创建一个代理类,将方法foo
指定为需要拦截的方法,并使用MethodDelegation.to
方法来指定拦截器的实现类SomeInterceptor
。最后我们使用make
方法来生成代理类的字节码,并使用load
方法将其加载到 JVM 中。
Class<?> proxyClass = new ByteBuddy()
.with(new NamingStrategy.SuffixingRandom("Proxy"))
.with(new TypeValidation.Disabled())
.subclass(SomeClass.class)
.method(named("foo"))
.intercept(MethodDelegation.to(SomeInterceptor.class))
.make()
.load(SomeClass.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
2.2.2 ByteBuddy 库的主要特性和使用示例
2.2.2.1 动态代理
ByteBuddy 可以用于创建动态代理类,提供了一个 fluent API,非常容易上手。下面是一个创建动态代理类的示例:
在这个示例中,我们创建了一个实现
MyInterface
接口的动态代理类,拦截MyInterface
接口中的所有方法,并将其转发到MyInterceptor
类中的intercept
方法进行处理。最后,我们使用动态代理调用了foo
方法,并输出了相应的日志。
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.implementation.MethodDelegation;
public class Example {
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
MyInterface proxy = new ByteBuddy()
.subclass(MyInterface.class)
.method(isDeclaredBy(MyInterface.class))
.intercept(MethodDelegation.to(MyInterceptor.class))
.make()
.load(Example.class.getClassLoader())
.getLoaded()
.newInstance();
proxy.foo(); // 使用动态代理调用 foo 方法
}
}
interface MyInterface {
void foo();
}
class MyInterceptor {
public static void intercept(@Origin Method method) {
System.out.println("Before " + method.getName());
// 调用原始方法
System.out.println("After " + method.getName());
}
}
2.2.2.2 动态运行时修改类
ByteBuddy 可以用于在运行时修改现有的类。下面是一个示例:
在这个示例中,我们重新定义了
SomeClass
类的foo
方法,将其返回值修改为 “Hello, World!”。然后,我们使用运行时生成的新类来创建一个实例,并调用foo
方法,输出了相应的结果。
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.implementation.FixedValue;
import net.bytebuddy.matcher.ElementMatchers;
public class Example {
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
String result = new ByteBuddy()
.redefine(SomeClass.class)
.method(ElementMatchers.named("foo"))
.intercept(FixedValue.value("Hello, World!"))
.make()
.load(Example.class.getClassLoader())
.getLoaded()
.newInstance()
.foo();
System.out.println(result); // 输出 "Hello, World!"
}
}
class SomeClass {
public String foo() {
return "Original implementation";
}
}
2.2.2.3 生成字节码
ByteBuddy 可以用于生成字节码。下面是一个示例:
在这个示例中,我们使用 ByteBuddy 生成了一个继承自
Object
类的新类,并重新定义了其toString
方法的行为。然后,我们将生成的类保存到指定目录中。
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.FixedValue;
import java.io.File;
import java.io.IOException;
public class Example {
public static void main(String[] args) throws IOException {
DynamicType.Unloaded<?> dynamicType = new ByteBuddy()
.subclass(Object.class)
.name("example.SomeClass")
.method(ElementMatchers.named("toString"))
.intercept(FixedValue.value("Hello, World!"))
.make();
dynamicType.saveIn(new File("build/classes/java/main"));
}
}
2.3 RedefinitionStrategy agent重定义扩展
定义已加载的类被 build agent 修改时的策略 …待更新
2.4 Transformer
字节码增强入口
@Override
public DynamicType.Builder<?> transform(final DynamicType.Builder<?> builder,
final TypeDescription typeDescription,
final ClassLoader classLoader
final JavaModule module) {
// 获取所有插件,待增强的
List<AbstractClassEnhancePluginDefine> pluginDefines = pluginFinder.find(typeDescription);
if (pluginDefines.size() > 0) {
DynamicType.Builder<?> newBuilder = builder;
EnhanceContext context = new EnhanceContext();
for (AbstractClassEnhancePluginDefine define : pluginDefines) {
DynamicType.Builder<?> possibleNewBuilder = define.define(
typeDescription, newBuilder, classLoader, context);
// 是否增强了,是的话使用增强的 builder
if (possibleNewBuilder != null) {
newBuilder = possibleNewBuilder;
}
}
if (context.isEnhanced()) {
LOGGER.debug("Finish the prepare stage for {}.", typeDescription.getName());
}
return newBuilder;
}
LOGGER.debug("Matched class {}, but ignore by finding mechanism.", typeDescription.getTypeName());
return builder;
}
三、SnifferConfigInitializer
初始化所有配置
3.1 initializeCoreConfig 初始化核心配置
如果有指定参数配置,则加载指定参数,如果没有,则加载 agent.config 配置文件内配置,其定义在 /config 目录下。同样也可以通过系统参数覆盖配置,所有的键应当以 skywalking.
开头。例如 skywalking.agent.service_name=yourAppName
会覆盖 agent.service_name
/**
* If the specified agent config path is set, the agent will try to locate the specified agent config. If the
* specified agent config path is not set , the agent will try to locate `agent.config`, which should be in the
* /config directory of agent package.
* <p>
* Also try to override the config by system.properties. All the keys in this place should start with {@link
* #ENV_KEY_PREFIX}. e.g. in env `skywalking.agent.service_name=yourAppName` to override `agent.service_name` in
* config file.
* <p>
* At the end, `agent.service_name` and `collector.servers` must not be blank.
*/
public static void initializeCoreConfig(String agentOptions) {
AGENT_SETTINGS = new Properties();
//加载 /config/agent.config
try (final InputStreamReader configFileStream = loadConfig()) {
// key value 加载进 AGENT_SETTINGS
AGENT_SETTINGS.load(configFileStream);
for (String key : AGENT_SETTINGS.stringPropertyNames()) {
String value = (String) AGENT_SETTINGS.get(key);
// 对配置文件参数做了一些替换
// 比如 把 collector.backend_service=${SW_AGENT_COLLECTOR_BACKEND_SERVICES:127.0.0.1:11800}
// 替换为 collector.backend_service=127.0.0.1:11800
AGENT_SETTINGS.put(key, PropertyPlaceholderHelper.INSTANCE.replacePlaceholders(value, AGENT_SETTINGS));
}
} catch (Exception e) {
LOGGER.error(e, "Failed to read the config file, skywalking is going to run in default config.");
}
try {
// 系统参数覆盖 把 skywalking. 开头的参数覆盖到 agent.conf 参数中
// 例如 skywalking.collector.backend_service 覆盖到 collector.backend_service 中
overrideConfigBySystemProp();
} catch (Exception e) {
LOGGER.error(e, "Failed to read the system properties.");
}
agentOptions = StringUtil.trim(agentOptions, ',');
if (!StringUtil.isEmpty(agentOptions)) {
try {
agentOptions = agentOptions.trim();
LOGGER.info("Agent options is {}.", agentOptions);
// agent 后参数设置
overrideConfigByAgentOptions(agentOptions);
} catch (Exception e) {
LOGGER.error(e, "Failed to parse the agent options, val is {}.", agentOptions);
}
}
// 处理华配置文件,将配置文件内的 key value 映射到 config 静态字段
initializeConfig(Config.class);
// 日志配置加载 两种模式 patten 及 json 默认 patten
configureLogger();
// 根据配置重新加载 logger
LOGGER = LogManager.getLogger(SnifferConfigInitializer.class);
if (StringUtil.isEmpty(Config.Agent.SERVICE_NAME)) {
throw new ExceptionInInitializerError("`agent.service_name` is missing.");
}
if (StringUtil.isEmpty(Config.Collector.BACKEND_SERVICE)) {
throw new ExceptionInInitializerError("`collector.backend_service` is missing.");
}
// 插件的 peer 字段长度校验
if (Config.Plugin.PEER_MAX_LENGTH <= 3) {
LOGGER.warn(
"PEER_MAX_LENGTH configuration:{} error, the default value of 200 will be used.",
Config.Plugin.PEER_MAX_LENGTH
);
Config.Plugin.PEER_MAX_LENGTH = 200;
}
IS_INIT_COMPLETED = true;
}
四、PluginBootstrap
寻找插件组件,使用 PluginResourcesResolver 去寻找所有的插件,调用 PluginCfg 加载所有的插件定义
4.1 loadPlugins 加载所有插件
返回所有插件定义、AbstractClassEnhancePluginDefine 为插件的顶级抽象
/**
* load all plugins.
*
* @return plugin definition list.
*/
public List<AbstractClassEnhancePluginDefine> loadPlugins() throws AgentPackageNotFoundException {
// 初始化一个 classloader ,用来加载 skywalking 类,详情见 《第五章 AgentClassLoader 5.2 节 initDefaultLoader》
AgentClassLoader.initDefaultLoader();
// 加载插件定义资源详情查看第六章 PluginResourcesResolver
PluginResourcesResolver resolver = new PluginResourcesResolver();
// 加载到所有插件定义文件所在路径
List<URL> resources = resolver.getResources();
if (resources == null || resources.size() == 0) {
LOGGER.info("no plugin files (skywalking-plugin.def) found, continue to start application.");
return new ArrayList<AbstractClassEnhancePluginDefine>();
}
for (URL pluginUrl : resources) {
try {
// 初始化配置插件 详情见 第七章 PluginCfg 插件配置类
PluginCfg.INSTANCE.load(pluginUrl.openStream());
} catch (Throwable t) {
LOGGER.error(t, "plugin file [{}] init failure.", pluginUrl);
}
}
// 拿到上一步加载到的插件插件定义
List<PluginDefine> pluginClassList = PluginCfg.INSTANCE.getPluginClassList();
List<AbstractClassEnhancePluginDefine> plugins = new ArrayList<AbstractClassEnhancePluginDefine>();
for (PluginDefine pluginDefine : pluginClassList) {
try {
LOGGER.debug("loading plugin class {}.", pluginDefine.getDefineClass());
// 根据定义加载插件示例,并添加到插件列表中
AbstractClassEnhancePluginDefine plugin = (AbstractClassEnhancePluginDefine) Class.forName(pluginDefine.getDefineClass(), true, AgentClassLoader
.getDefault()).newInstance();
plugins.add(plugin);
} catch (Throwable t) {
LOGGER.error(t, "load plugin [{}] failure.", pluginDefine.getDefineClass());
}
}
// 实现 spi 插件加载
plugins.addAll(DynamicPluginLoader.INSTANCE.load(AgentClassLoader.getDefault()));
return plugins;
}
五、 AgentClassLoader
The AgentClassLoader
represents a classloader, which is in charge of finding plugins and interceptors. 代表一个类加载器,负责加载找到的插件及拦截器。 继承自 ClassLoader
5.1 registerAsParallelCapable
调用父类 ClassLoader 的 registerAsParallelCapable ,将其注册为具有并行能力的类加载器
/*
* Try to solve the classloader dead lock. See https://github.com/apache/skywalking/pull/2016
*/
registerAsParallelCapable();
ClassLoader 的实现
@CallerSensitive
protected static boolean registerAsParallelCapable() {
// 获取到当前调用的类的类加载器
Class<? extends ClassLoader> callerClass =
Reflection.getCallerClass().asSubclass(ClassLoader.class);
// 并行注册
return ParallelLoaders.register(callerClass);
}
/**
* Registers the given class loader type as parallel capable.
* Returns {@code true} is successfully registered; {@code false} if
* loader's super class is not registered.
*/
static boolean register(Class<? extends ClassLoader> c) {
synchronized (loaderTypes) {
// 父类加载器如果是并行的才允许具备并行能力
if (loaderTypes.contains(c.getSuperclass())) {
// register the class loader as parallel capable
// if and only if all of its super classes are.
// Note: given current classloading sequence, if
// the immediate super class is parallel capable,
// all the super classes higher up must be too.
loaderTypes.add(c);
return true;
} else {
return false;
}
}
}
5.2 initDefaultLoader 初始化默认类加载器
public static void initDefaultLoader() throws AgentPackageNotFoundException {
// 同步锁,保证单例
if (DEFAULT_LOADER == null) {
synchronized (AgentClassLoader.class) {
if (DEFAULT_LOADER == null) {
DEFAULT_LOADER = new AgentClassLoader(PluginBootstrap.class.getClassLoader());
}
}
}
}
5.3 AgentClassLoader 构造方法
public AgentClassLoader(ClassLoader parent) throws AgentPackageNotFoundException {
super(parent);
// 查找包路径
File agentDictionary = AgentPackagePath.getPath();
classpath = new LinkedList<>();
// public static List<String> MOUNT = Arrays.asList("plugins", "activations");
// Config.Plugin.MOUNT 定义为数组,加载包路径下 /plugins /activations 所有的类
Config.Plugin.MOUNT.forEach(mountFolder -> classpath.add(new File(agentDictionary, mountFolder)));
}
六、PluginResourcesResolver 插件资源查找器
Use the current classloader to read all plugin define file. The file must be named ‘skywalking-plugin.def’ 使用当前的类加载器加载所有的插件定义文件,文件名必须为 ```skywalking-plugin.def```
public List<URL> getResources() {
List<URL> cfgUrlPaths = new ArrayList<URL>();
Enumeration<URL> urls;
...
// 类加载器加载资源
urls = AgentClassLoader.getDefault().getResources("skywalking-plugin.def");
while (urls.hasMoreElements()) {
URL pluginUrl = urls.nextElement();
cfgUrlPaths.add(pluginUrl);
LOGGER.info("find skywalking plugin define in {}", pluginUrl);
}
...
return null;
}
以 dubbo 插件为例,其找到插件定义路径后返回
![image-20230220151405820](/Users/qianyuhua/Library/Application%20Support/typora-user-images/image-20230220151405820.png)
七、PluginCfg 插件配置类
使用枚举类型,形成单例模式,其将插件 封装为 ```PluginDefine```
...
private List<PluginDefine> pluginClassList = new ArrayList<PluginDefine>();
private PluginSelector pluginSelector = new PluginSelector();
...
// pluginDefine 就是 dubbo=org*.....
PluginDefine plugin = PluginDefine.build(pluginDefine);
pluginClassList.add(plugin);
...
// 此处过滤不需要激活的插件,配置文件可配置x
pluginClassList = pluginSelector.select(pluginClassList);
八、PluginFinder 查询查找器
通过需要被增强的类查找插件
8.1 PluginFinder 构造查找器信息
私有变量,存储各插件对应规则
// 名称匹配器对应规则的插件 key 为增强类,value 为增强插件
private final Map<String, LinkedList<AbstractClassEnhancePluginDefine>> nameMatchDefine = new HashMap<String, LinkedList<AbstractClassEnhancePluginDefine>>();
// 除名称匹配器对应规则的插件列表
private final List<AbstractClassEnhancePluginDefine> signatureMatchDefine = new ArrayList<AbstractClassEnhancePluginDefine>();
// bootstrap classloader 类加载器加载的类
private final List<AbstractClassEnhancePluginDefine> bootstrapClassMatchDefine = new ArrayList<AbstractClassEnhancePluginDefine>();
8.2 find 查找插件
public List<AbstractClassEnhancePluginDefine> find(TypeDescription typeDescription) {
List<AbstractClassEnhancePluginDefine> matchedPlugins = new LinkedList<AbstractClassEnhancePluginDefine>();
String typeName = typeDescription.getTypeName();
// 如果是名称匹配器,按照名称查找
if (nameMatchDefine.containsKey(typeName)) {
matchedPlugins.addAll(nameMatchDefine.get(typeName));
}
// 如或是其他类型匹配器,按照 isMatch 方法匹配
for (AbstractClassEnhancePluginDefine pluginDefine : signatureMatchDefine) {
IndirectMatch match = (IndirectMatch) pluginDefine.enhanceClass();
if (match.isMatch(typeDescription)) {
matchedPlugins.add(pluginDefine);
}
}
return matchedPlugins;
}
8.3 buildMatch 匹配增强类
public ElementMatcher<? super TypeDescription> buildMatch() {
// 先定一个名称匹配器
ElementMatcher.Junction judge = new AbstractJunction<NamedElement>() {
@Override
public boolean matches(NamedElement target) {
// 是否包含在已完成名称匹配列表中
return nameMatchDefine.containsKey(target.getActualName());
}
};
// 并且不是接口
judge = judge.and(not(isInterface()));
for (AbstractClassEnhancePluginDefine define : signatureMatchDefine) {
ClassMatch match = define.enhanceClass();
if (match instanceof IndirectMatch) {
// 或者 满足了某种自定义匹配器
judge = judge.or(((IndirectMatch) match).buildJunction());
}
}
return new ProtectiveShieldMatcher(judge);
}
九、BootstrapInstrumentBoost
9.1 inject 注入
public static AgentBuilder inject(PluginFinder pluginFinder, Instrumentation instrumentation,
AgentBuilder agentBuilder, JDK9ModuleExporter.EdgeClasses edgeClasses) throws PluginException {
Map<String, byte[]> classesTypeMap = new HashMap<String, byte[]>();
// 将插件的增强处理类注入到 jre 的环境里面去
if (!prepareJREInstrumentation(pluginFinder, classesTypeMap)) {
return agentBuilder;
}
// 加载高优先级的类
for (String highPriorityClass : HIGH_PRIORITY_CLASSES) {
loadHighPriorityClass(classesTypeMap, highPriorityClass);
}
// byte-buddy 核心类
for (String highPriorityClass : ByteBuddyCoreClasses.CLASSES) {
loadHighPriorityClass(classesTypeMap, highPriorityClass);
}
/**
* Prepare to open edge of necessary classes. 所有边缘类
*/
for (String generatedClass : classesTypeMap.keySet()) {
edgeClasses.add(generatedClass);
}
/**
* Inject the classes into bootstrap class loader by using Unsafe Strategy.
* ByteBuddy adapts the sun.misc.Unsafe and jdk.internal.misc.Unsafe automatically.
*/
// 把所有的核心类注入到 bootstrap 里面,保证 bootstrap 类能够访问到
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;
}
9.2 forInternalDelegateClass
从当前类的类加载器(AgentClassloader)加载一个委托类来处理增强的具体逻辑
/**
* Load the delegate class from current class loader, mostly should be AppClassLoader.
*
* @param methodsInterceptor of original interceptor in the plugin
* @return generated delegate class
*/
public static Class forInternalDelegateClass(String methodsInterceptor) {
try {
// 通过 agentClassloader 加载一个 interceptor 类出来
// 双亲委派机制,从自定义 agentClassloader 一直向上查找
// 这个类是如何被加载到的? 看详情 本章第 9.1 节 prepareJREInstrumentation 方法
return Class.forName(internalDelegate(methodsInterceptor));
} catch (ClassNotFoundException e) {
throw new PluginException(e.getMessage(), e);
}
}
9.3 internalDelegate
获取一个委托类的名称
/**
* Get the delegate class name.
*
* @param methodsInterceptor of original interceptor in the plugin
* @return generated delegate class name
*/
public static String internalDelegate(String methodsInterceptor) {
return methodsInterceptor + "_internal";
}
9.4 prepareJREInstrumentation
这个地方比较绕
/**
* Generate dynamic delegate for ByteBuddy
*
* @param pluginFinder gets the whole plugin list.
* @param classesTypeMap hosts the class binary.
* @return true if have JRE instrumentation requirement.
* @throws PluginException when generate failure.
*/
private static boolean prepareJREInstrumentation(PluginFinder pluginFinder,
Map<String, byte[]> classesTypeMap) throws PluginException {
// 获取到 BootstrapInstrumentBoost 类加载器的类型池
TypePool typePool = TypePool.Default.of(BootstrapInstrumentBoost.class.getClassLoader());
// 获取到插件
List<AbstractClassEnhancePluginDefine> bootstrapClassMatchDefines = pluginFinder.getBootstrapClassMatchDefine();
for (AbstractClassEnhancePluginDefine define : bootstrapClassMatchDefines) {
// 实例方法
for (InstanceMethodsInterceptPoint point : define.getInstanceMethodsInterceptPoints()) {
// 是否覆盖参数
if (point.isOverrideArgs()) {
generateDelegator(classesTypeMap, typePool, INSTANCE_METHOD_WITH_OVERRIDE_ARGS_DELEGATE_TEMPLATE, point
.getMethodsInterceptor());
} else {
// 生成委托类
generateDelegator(classesTypeMap, typePool, INSTANCE_METHOD_DELEGATE_TEMPLATE, point.getMethodsInterceptor());
}
}
// 构造器
for (ConstructorInterceptPoint point : define.getConstructorsInterceptPoints()) {
generateDelegator(classesTypeMap, typePool, CONSTRUCTOR_DELEGATE_TEMPLATE, point.getConstructorInterceptor());
}
// 静态方法
for (StaticMethodsInterceptPoint point : define.getStaticMethodsInterceptPoints()) {
if (point.isOverrideArgs()) {
generateDelegator(classesTypeMap, typePool, STATIC_METHOD_WITH_OVERRIDE_ARGS_DELEGATE_TEMPLATE, point
.getMethodsInterceptor());
} else {
generateDelegator(classesTypeMap, typePool, STATIC_METHOD_DELEGATE_TEMPLATE, point.getMethodsInterceptor());
}
}
}
return bootstrapClassMatchDefines.size() > 0;
}
9.5 generateDelegator
通过一个模板类来生成一个委托类,来处理增强逻辑, 下述 One key step to avoid class confliction between AppClassLoader and BootstrapClassLoader
这句话很关键,为什么说是 AppClassLoader
及 BootstrapClassLoader
关键的一步?
个人理解:
增强的原理是修改原原始目标类的字节码,添加相应增强逻辑上去。 当增强 JDK 类时,会引入一些属于 skywalking 的功能,此时会造成 jdk 类访问不到 skywalking 类的功能。
所以以下方法提供了一个关键步骤,就是通过一个模版(详情见 本章第 9.6 节 InstanceMethodInterTemplate),将这个模版加载为一个描述,后续通过 bytebuddy 修改,生层新的类。
- 类名称:调用 internalDelegate() 方法(本章 第 3 节),生成原 InterceptorName 后加 + _internal 的名称。例如 org.apache.skywalking.apm.plugin.ons.MessageListenerAdapterInterceptor 会变成 org.apache.skywalking.apm.plugin.ons.MessageListenerAdapterInterceptor_internal
- 字段赋值: TARGET_INTERCEPTOR 赋值为 InterceptorName 。例如 TARGET_INTERCEPTOR = org.apache.skywalking.apm.plugin.ons.MessageListenerAdapterInterceptor
/**
* Generate the delegator class based on given template class. This is preparation stage level code generation.
* <p>
* One key step to avoid class confliction between AppClassLoader and BootstrapClassLoader
*
* @param classesTypeMap hosts injected binary of generated class
* @param typePool to generate new class
* @param templateClassName represents the class as template in this generation process. The templates are
* pre-defined in SkyWalking agent core.
*/
private static void generateDelegator(Map<String, byte[]> classesTypeMap, TypePool typePool,
String templateClassName, String methodsInterceptor) {
// 获取加后缀的 Interceptor Interceptor_internal
String internalInterceptorName = internalDelegate(methodsInterceptor);
try {
// 获取到模版文件的描述
TypeDescription templateTypeDescription = typePool.describe(templateClassName).resolve();
// 生成新的类
DynamicType.Unloaded interceptorType = new ByteBuddy().redefine(templateTypeDescription, ClassFileLocator.ForClassLoader
.of(BootstrapInstrumentBoost.class.getClassLoader()))
.name(internalInterceptorName)
.field(named("TARGET_INTERCEPTOR"))
.value(methodsInterceptor)
.make();
// 放到 map 当中
classesTypeMap.put(internalInterceptorName, interceptorType.getBytes());
InstrumentDebuggingClass.INSTANCE.log(interceptorType);
} catch (Exception e) {
throw new PluginException("Generate Dynamic plugin failure", e);
}
}
9.6 InstanceMethodInterTemplate
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.agent.core.plugin.bootstrap.template;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;
import net.bytebuddy.implementation.bind.annotation.This;
import org.apache.skywalking.apm.agent.core.plugin.bootstrap.IBootstrapLog;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.BootstrapInterRuntimeAssist;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
/**
* --------CLASS TEMPLATE---------
* <p>Author, Wu Sheng </p>
* <p>Comment, don't change this unless you are 100% sure the agent core mechanism for bootstrap class
* instrumentation.</p>
* <p>Date, 24th July 2019</p>
* -------------------------------
* <p>
* This class wouldn't be loaded in real env. This is a class template for dynamic class generation.
*/
public class InstanceMethodInterTemplate {
/**
* This field is never set in the template, but has value in the runtime.
*/
private static String TARGET_INTERCEPTOR;
private static InstanceMethodsAroundInterceptor INTERCEPTOR;
private static IBootstrapLog LOGGER;
/**
* Intercept the target instance method.
*
* @param obj target class instance.
* @param allArguments all method arguments
* @param method method description.
* @param zuper the origin call ref.
* @return the return value of target instance method.
* @throws Exception only throw exception because of zuper.call() or unexpected exception in sky-walking ( This is a
* bug, if anything triggers this condition ).
*/
@RuntimeType
public static Object intercept(@This Object obj, @AllArguments Object[] allArguments, @SuperCall Callable<?> zuper,
@Origin Method method) throws Throwable {
EnhancedInstance targetObject = (EnhancedInstance) obj;
// 模版与 InstanceMethodInter 的区别就在这一句话
prepare();
MethodInterceptResult result = new MethodInterceptResult();
try {
if (INTERCEPTOR != null) {
INTERCEPTOR.beforeMethod(targetObject, method, allArguments, method.getParameterTypes(), result);
}
} catch (Throwable t) {
if (LOGGER != null) {
LOGGER.error(t, "class[{}] before method[{}] intercept failure", obj.getClass(), method.getName());
}
}
Object ret = null;
try {
if (!result.isContinue()) {
ret = result._ret();
} else {
ret = zuper.call();
}
} catch (Throwable t) {
try {
if (INTERCEPTOR != null) {
INTERCEPTOR.handleMethodException(targetObject, method, allArguments, method.getParameterTypes(), t);
}
} catch (Throwable t2) {
if (LOGGER != null) {
LOGGER.error(t2, "class[{}] handle method[{}] exception failure", obj.getClass(), method.getName());
}
}
throw t;
} finally {
try {
if (INTERCEPTOR != null) {
ret = INTERCEPTOR.afterMethod(targetObject, method, allArguments, method.getParameterTypes(), ret);
}
} catch (Throwable t) {
if (LOGGER != null) {
LOGGER.error(t, "class[{}] after method[{}] intercept failure", obj.getClass(), method.getName());
}
}
}
return ret;
}
/**
* Prepare the context. Link to the agent core in AppClassLoader.
*/
private static void prepare() {
if (INTERCEPTOR == null) {
// 加载了 agent class loader 详情见 第十五章 BootstrapInterRuntimeAssist 15.1 节
ClassLoader loader = BootstrapInterRuntimeAssist.getAgentClassLoader();
if (loader != null) {
// 加载 logger
IBootstrapLog logger = BootstrapInterRuntimeAssist.getLogger(loader, TARGET_INTERCEPTOR);
if (logger != null) {
LOGGER = logger;
// 加载具体增强逻辑的 interceptor
INTERCEPTOR = BootstrapInterRuntimeAssist.createInterceptor(loader, TARGET_INTERCEPTOR, LOGGER);
}
} else {
LOGGER.error("Runtime ClassLoader not found when create {}." + TARGET_INTERCEPTOR);
}
}
}
}
十、ServiceManager
The ServiceManager
bases on {@link ServiceLoader}, load all {@link BootService} implementations. 服务管理器,加载所有 Bootservice 的实现。
10.1 boot
public void boot() {
// 详情见 本章 10.2 loadAllServices
bootedServices = loadAllServices();
prepare();
startup();
onComplete();
}
10.2 loadAllServices
加载所有服务,并且保证服务只有一个实现
private 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) {
// 如果是默认实现,并且加入 map
if (!bootedServices.containsKey(bootServiceClass)) {
bootedServices.put(bootServiceClass, bootService);
} else {
//ignore the default service
}
} else {
// 是否是覆盖实现
OverrideImplementor overrideImplementor = bootServiceClass.getAnnotation(OverrideImplementor.class);
if (overrideImplementor == null) {
// map 内没有这个服务class
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;
}
// spi 查询所有的 bootservice 实现
void load(List<BootService> allServices) {
for (final BootService bootService : ServiceLoader.load(BootService.class, AgentClassLoader.getDefault())) {
allServices.add(bootService);
}
}
10.2.1 以 JVMMetricsSender 为例
JVMMetricsSender 为发送 JVMService 采集 JVM 参数数据的 service,其为默认实现
@DefaultImplementor
public class JVMService implements BootService, Runnable {}
另外还有两个实现
@OverrideImplementor(JVMMetricsSender.class)
public class RocketMqJVMMetricsSender extends JVMMetricsSender {}
@OverrideImplementor(JVMMetricsSender.class)
public class KafkaJVMMetricsSender extends JVMMetricsSender {}
10.3 prepare
#### 10.3.1 按照服务优先级调用 prepare 方法
private void prepare() {
bootedServices.values().stream().sorted(Comparator.comparingInt(BootService::priority)).forEach(service -> {
try {
service.prepare();
} catch (Throwable e) {
LOGGER.error(e, "ServiceManager try to pre-start [{}] fail.", service.getClass().getName());
}
});
}
10.3.2 以 JVMService 服务为例
其 prepare 方法,初始化了一个数据发送服务,用来发送 jvm service 采集的参数, 初始化的值为 10.2.1 其中一个
@Override
public void prepare() throws Throwable {
sender = ServiceManager.INSTANCE.findService(JVMMetricsSender.class);
}
10.4 startup
10.4.1 按照服务优先级调用 boot 方法
private void startup() {
bootedServices.values().stream().sorted(Comparator.comparingInt(BootService::priority)).forEach(service -> {
try {
service.boot();
} catch (Throwable e) {
LOGGER.error(e, "ServiceManager try to start [{}] fail.", service.getClass().getName());
}
});
}
10.4.2 以 JVMService 服务为例
服务启动了两个线程池,跑了两个定时任务,第一是采集 jvm 数据, 第二个是发送采集数据
@Override
public void boot() throws Throwable {
collectMetricFuture = Executors.newSingleThreadScheduledExecutor(new DefaultNamedThreadFactory("JVMService-produce")).scheduleAtFixedRate(new RunnableWithExceptionProtection(this, new RunnableWithExceptionProtection.CallbackWhenException() {
@Override
public void handle(Throwable t) {
LOGGER.error("JVMService produces metrics failure.", t);
}
}), 0, 1, TimeUnit.SECONDS);
sendMetricFuture = Executors.newSingleThreadScheduledExecutor(new DefaultNamedThreadFactory("JVMService-consume")).scheduleAtFixedRate(new RunnableWithExceptionProtection(sender, new RunnableWithExceptionProtection.CallbackWhenException() {
@Override
public void handle(Throwable t) {
LOGGER.error("JVMService consumes and upload failure.", t);
}
}), 0, 1, TimeUnit.SECONDS);
}
10.5 onComplete
10.5.1 调用服务 onComplate 方法
private void onComplete() {
for (BootService service : bootedServices.values()) {
try {
service.onComplete();
} catch (Throwable e) {
LOGGER.error(e, "Service [{}] AfterBoot process fails.", service.getClass().getName());
}
}
}
10.5.2 以 JVMService 服务为例
空实现
@Override
public void onComplete() throws Throwable {
}
十一、 AbstractClassEnhancePluginDefine
Basic abstract class of all sky-walking auto-instrumentation plugins.所有插件最基础的抽象定义类
11.1 define
Main entrance of enhancing the class. 增强的主入口类
/**
*
* @param typeDescription target class description. 要增强的目标类描述
* @param builder byte-buddy's builder to manipulate target class's bytecode. 包含原字节码及要增强的字节码操作
* @param classLoader load the given transformClass 类加载器
* @return the new builder, or <code>null</code> if not be enhanced.
* @throws PluginException when set builder failure.
*/
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) {
// 详情见 WitnessFinder 第十二章 12.2 节
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) {
// 详情见 WitnessFinder 第十二章 12.1 节
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
* 增强 详情见本章 11.2 节
*/
DynamicType.Builder<?> newClassBuilder = this.enhance(typeDescription, builder, classLoader, context);
// 打标记,表示类增强完毕
context.initializationStageCompleted();
LOGGER.debug("enhance class {} by {} completely.", transformClassName, interceptorDefineClassName);
return newClassBuilder;
}
11.2 enhance
抽象方法,交给子类实现,定义自己的增强逻辑
现在只有一个插件增强类,详情见 第十三章 ClassEnhancePluginDefine 13.1 节
protected abstract DynamicType.Builder<?> enhance(TypeDescription typeDescription,
DynamicType.Builder<?> newClassBuilder, ClassLoader classLoader, EnhanceContext context) throws PluginException;
十二、 WitnessFinder
枚举类型,实现单例
The WitnessFinder
represents a pool of {@link TypePool}s, each {@link TypePool} matches a {@linkClassLoader}, which helps to find the class declaration existed or not.
WitnessFinder 表示一个 TypePool 的池子,每一个 TypePool 匹配一个 linkClassLoader,用于查找声明的 class 是否存在
private final Map<ClassLoader, TypePool> poolMap = new HashMap<ClassLoader, TypePool>();
12.1 exist 基于 class 类识别
该方法的实现主要是通过调用getResolution(witnessClass, classLoader)方法获取到对应的Class文件解析器,然后判断该解析器是否已经解析完成,如果解析完成,则说明该类已经存在于ClassLoader中,方法返回true;否则说明该类不存在于ClassLoader中,方法返回false。
具体而言,该方法的实现步骤如下:
- 调用getResolution(witnessClass, classLoader)方法获取到对应的Class文件解析器;
- 调用isResolved()方法判断该解析器是否已经解析完成;
- 如果已经解析完成,则返回true;否则返回false。
需要注意的是,该方法只能用于判断指定类是否已经被加载,无法判断该类是否能够被正确初始化。因此,在使用该方法时,需要谨慎考虑是否满足业务需求。
/**
* @param classLoader for finding the witnessClass
* @return true, if the given witnessClass exists, through the given classLoader.
*/
public boolean exist(String witnessClass, ClassLoader classLoader) {
return getResolution(witnessClass, classLoader)
.isResolved();
}
12.2 exist 基于 方法 识别
/**
* @param classLoader for finding the witness method
* @return true, if the given witness method exists, through the given classLoader.
*/
public boolean exist(WitnessMethod witnessMethod, ClassLoader classLoader) {
// 与上述方法基本一致,也是获取到类的解析器,然后鉴别是否解析完成
TypePool.Resolution resolution = getResolution(witnessMethod.getDeclaringClassName(), classLoader);
if (!resolution.isResolved()) {
return false;
}
// 区别在下方, 又做了一次方法匹配
return !resolution.resolve()
.getDeclaredMethods()
.filter(witnessMethod.getElementMatcher())
.isEmpty();
}
12.3 其他抽象方法
// 是不是 Bootstrap 类加载器加载的
public boolean isBootstrapInstrumentation() {
return false;
}
// 以下三个都返回了一个拦截器数据,代表每个插件都可以对一个类中的多种构造器,实例方法,静态方法进行增强
// 其中包含 具体增强点 及 如何增强的实现器
/**
* Constructor methods intercept point. See {@link ConstructorInterceptPoint}
* 定义了拦截器的拦截点
*
* @return collections of {@link ConstructorInterceptPoint}
*/
public abstract ConstructorInterceptPoint[] getConstructorsInterceptPoints();
/**
* Instance methods intercept point. See {@link InstanceMethodsInterceptPoint}
* 定义了实例方法的拦截点
* @return collections of {@link InstanceMethodsInterceptPoint}
*/
public abstract InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints();
/**
* Static methods intercept point. See {@link StaticMethodsInterceptPoint}
* 定义了静态方法的拦截点
* @return collections of {@link StaticMethodsInterceptPoint}
*/
public abstract StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints();
十三、ClassEnhancePluginDefine
定义插件拦截增强的细节,及增强操作具体实现逻辑
- 增强操作:constructors 、instance methods、static methods
13.1 enhance
调用 enhanceClass, enhanceInstance 两种方法
@Override
protected DynamicType.Builder<?> enhance(TypeDescription typeDescription, DynamicType.Builder<?> newClassBuilder,
ClassLoader classLoader, EnhanceContext context) throws PluginException {
newClassBuilder = this.enhanceClass(typeDescription, newClassBuilder, classLoader);
newClassBuilder = this.enhanceInstance(typeDescription, newClassBuilder, classLoader, context);
return newClassBuilder;
}
13.2 enhanceInstance
Enhance a class to intercept constructors and class instance methods.
增强构造器及实例方法
/**
* Enhance a class to intercept constructors and class instance methods.
*
* @param typeDescription target class description
* @param newClassBuilder byte-buddy's builder to manipulate class bytecode.
* @return new byte-buddy's builder for further manipulation.
*/
private DynamicType.Builder<?> enhanceInstance(TypeDescription typeDescription,
DynamicType.Builder<?> newClassBuilder, ClassLoader classLoader,
EnhanceContext context) throws PluginException {
// 获取构造方法增强点
ConstructorInterceptPoint[] constructorInterceptPoints = getConstructorsInterceptPoints();
// 获取实例方法增强点
InstanceMethodsInterceptPoint[] instanceMethodsInterceptPoints = getInstanceMethodsInterceptPoints();
// 增强的类名称
String enhanceOriginClassName = typeDescription.getTypeName();
// 是否增强构造器
boolean existedConstructorInterceptPoint = false;
if (constructorInterceptPoints != null && constructorInterceptPoints.length > 0) {
existedConstructorInterceptPoint = true;
}
// 是否增强实例方法
boolean existedMethodsInterceptPoints = false;
if (instanceMethodsInterceptPoints != null && instanceMethodsInterceptPoints.length > 0) {
existedMethodsInterceptPoints = true;
}
/**
* 都不需要则返回原始增强类的 newClassBuilder
* nothing need to be enhanced in class instance, maybe need enhance static methods.
*/
if (!existedConstructorInterceptPoint && !existedMethodsInterceptPoints) {
return newClassBuilder;
}
/**
* Manipulate class source code.<br/>
*
* new class need:<br/>
* 1.Add field, name {@link #CONTEXT_ATTR_NAME}.
* 2.Add a field accessor for this field.
*
* And make sure the source codes manipulation only occurs once.
*
*/
// 主要是说 EnhancedInstance 当前被增强的类是不是实现了 EnhancedInstance 接口
if (!typeDescription.isAssignableTo(EnhancedInstance.class)) {
// 上下文标记字段类是否增强了,默认是 否
if (!context.isObjectExtended()) {
// 当上述条件为 true 是,给增强类实现下 EnhancedInstance 的两个方法
// 方便后续操作传递些信息
newClassBuilder = newClassBuilder.defineField(
CONTEXT_ATTR_NAME, Object.class, ACC_PRIVATE | ACC_VOLATILE)
.implement(EnhancedInstance.class)
.intercept(FieldAccessor.ofField(CONTEXT_ATTR_NAME));
context.extendObjectCompleted();
}
}
/**
* 2. enhance constructors
*/
if (existedConstructorInterceptPoint) {
for (ConstructorInterceptPoint constructorInterceptPoint : constructorInterceptPoints) {
// 是否 bootstrap loader 加载器
if (isBootstrapInstrumentation()) {
newClassBuilder =
// 构造匹配器,匹配出需要拦截构造器
newClassBuilder.constructor(constructorInterceptPoint.getConstructorMatcher())
//
.intercept(SuperMethodCall.INSTANCE.andThen(
MethodDelegation.withDefaultConfiguration()
// 详情见 第九章
.to(BootstrapInstrumentBoost.forInternalDelegateClass(constructorInterceptPoint
.getConstructorInterceptor()))));
} else {
newClassBuilder =
// 构造匹配器,匹配出需要拦截构造器
newClassBuilder.constructor(constructorInterceptPoint.getConstructorMatcher())
// 拦截上述构造器,并且调用原始构造器之后,再执行定义的方法,getConstructorInterceptor
.intercept(SuperMethodCall.INSTANCE.andThen(MethodDelegation.withDefaultConfiguration()
// 详情见 第十四章 ConstructorInter 14.1 14.2 节
.to(new ConstructorInter(constructorInterceptPoint
.getConstructorInterceptor(), classLoader))));
}
}
}
/**
* 3. enhance instance methods
* 以下就举一个例子 InstMethodsInterWithOverrideArgs 见第十五章
*/
if (existedMethodsInterceptPoints) {
for (InstanceMethodsInterceptPoint instanceMethodsInterceptPoint : instanceMethodsInterceptPoints) {
String interceptor = instanceMethodsInterceptPoint.getMethodsInterceptor();
if (StringUtil.isEmpty(interceptor)) {
throw new EnhanceException("no InstanceMethodsAroundInterceptor define to enhance class " + enhanceOriginClassName);
}
ElementMatcher.Junction<MethodDescription> junction = not(isStatic()).and(instanceMethodsInterceptPoint.getMethodsMatcher());
if (instanceMethodsInterceptPoint instanceof DeclaredInstanceMethodsInterceptPoint) {
junction = junction.and(ElementMatchers.isDeclaredBy(typeDescription));
}
if (instanceMethodsInterceptPoint.isOverrideArgs()) {
if (isBootstrapInstrumentation()) {
newClassBuilder = newClassBuilder.method(junction)
.intercept(MethodDelegation.withDefaultConfiguration()
.withBinders(Morph.Binder.install(OverrideCallable.class))
.to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor)));
} else {
newClassBuilder = newClassBuilder.method(junction)
.intercept(MethodDelegation.withDefaultConfiguration()
.withBinders(Morph.Binder.install(OverrideCallable.class))
// 见第十五章 15.1
.to(new InstMethodsInterWithOverrideArgs(interceptor, classLoader)));
}
} else {
if (isBootstrapInstrumentation()) {
newClassBuilder = newClassBuilder.method(junction)
.intercept(MethodDelegation.withDefaultConfiguration()
.to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor)));
} else {
newClassBuilder = newClassBuilder.method(junction)
.intercept(MethodDelegation.withDefaultConfiguration()
.to(new InstMethodsInter(interceptor, classLoader)));
}
}
}
}
return newClassBuilder;
}
13.3 enhanceClass
Enhance a class to intercept class static methods.
/**
* Enhance a class to intercept class static methods.
*
* @param typeDescription target class description
* @param newClassBuilder byte-buddy's builder to manipulate class bytecode.
* @return new byte-buddy's builder for further manipulation.
*/
private DynamicType.Builder<?> enhanceClass(TypeDescription typeDescription, DynamicType.Builder<?> newClassBuilder,
ClassLoader classLoader) throws PluginException {
StaticMethodsInterceptPoint[] staticMethodsInterceptPoints = getStaticMethodsInterceptPoints();
String enhanceOriginClassName = typeDescription.getTypeName();
if (staticMethodsInterceptPoints == null || staticMethodsInterceptPoints.length == 0) {
return newClassBuilder;
}
for (StaticMethodsInterceptPoint staticMethodsInterceptPoint : staticMethodsInterceptPoints) {
String interceptor = staticMethodsInterceptPoint.getMethodsInterceptor();
if (StringUtil.isEmpty(interceptor)) {
throw new EnhanceException("no StaticMethodsAroundInterceptor define to enhance class " + enhanceOriginClassName);
}
if (staticMethodsInterceptPoint.isOverrideArgs()) {
if (isBootstrapInstrumentation()) {
newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher()))
.intercept(MethodDelegation.withDefaultConfiguration()
.withBinders(Morph.Binder.install(OverrideCallable.class))
.to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor)));
} else {
newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher()))
.intercept(MethodDelegation.withDefaultConfiguration()
.withBinders(Morph.Binder.install(OverrideCallable.class))
.to(new StaticMethodsInterWithOverrideArgs(interceptor)));
}
} else {
if (isBootstrapInstrumentation()) {
newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher()))
.intercept(MethodDelegation.withDefaultConfiguration()
.to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor)));
} else {
newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher()))
.intercept(MethodDelegation.withDefaultConfiguration()
.to(new StaticMethodsInter(interceptor)));
}
}
}
return newClassBuilder;
}
十四、 ConstructorInter
The actual byte-buddy’s interceptor to intercept constructor methods. In this class, it provide a bridge between byte-buddy and sky-walking plugin.
这个类把 skywalking 插件的增强类逻辑与 byte-buddy 的增强逻辑连接起来
14.1 ConstructorInter 构造器
/**
* @param constructorInterceptorClassName class full name.
*/
public ConstructorInter(String constructorInterceptorClassName, ClassLoader classLoader) throws PluginException {
try {
// 此逻辑是更具 类名称 查询到做增强逻辑的类
interceptor = InterceptorInstanceLoader.load(constructorInterceptorClassName, classLoader);
} catch (Throwable t) {
throw new PluginException("Can't create InstanceConstructorInterceptor.", t);
}
}
14.2 intercept
作者所说的桥梁,通过 byte-buddy 的逻辑,调用自定义 Interceptor 逻辑
/**
* Intercept the target constructor.
*
* @param obj target class instance.
* @param allArguments all constructor arguments
*/
@RuntimeType
public void intercept(@This Object obj, @AllArguments Object[] allArguments) {
try {
EnhancedInstance targetObject = (EnhancedInstance) obj;
interceptor.onConstruct(targetObject, allArguments);
} catch (Throwable t) {
LOGGER.error("ConstructorInter failure.", t);
}
}
十五、InstMethodsInterWithOverrideArgs
15.1 InstMethodsInterWithOverrideArgs
public InstMethodsInterWithOverrideArgs(String instanceMethodsAroundInterceptorClassName, ClassLoader classLoader) {
try {
// 加载一个 interceptor
interceptor = InterceptorInstanceLoader.load(instanceMethodsAroundInterceptorClassName, classLoader);
} catch (Throwable t) {
throw new PluginException("Can't create InstanceMethodsAroundInterceptor.", t);
}
}
15.2
实例方法拦截增强
/**
* Intercept the target instance method.
*
* @param obj target class instance.
* @param allArguments all method arguments
* @param method method description.
* @param zuper the origin call ref.
* @return the return value of target instance method.
* @throws Exception only throw exception because of zuper.call() or unexpected exception in sky-walking ( This is a
* bug, if anything triggers this condition ).
*/
@RuntimeType
public Object intercept(@This Object obj, @AllArguments Object[] allArguments, @Origin Method method,
@Morph OverrideCallable zuper) throws Throwable {
// 原始增强类的实例
EnhancedInstance targetObject = (EnhancedInstance) obj;
// 增强结果
MethodInterceptResult result = new MethodInterceptResult();
try {
// 类似 aop 懂得都懂
interceptor.beforeMethod(targetObject, method, allArguments, method.getParameterTypes(), result);
} catch (Throwable t) {
LOGGER.error(t, "class[{}] before method[{}] intercept failure", obj.getClass(), method.getName());
}
Object ret = null;
try {
// 判断是不是要继续要用,不调用的话直接可以返回。 这个值是可以设置的
if (!result.isContinue()) {
ret = result._ret();
} else {
// 调用原方法
ret = zuper.call(allArguments);
}
} catch (Throwable t) {
try {
// 类似 aop 懂得都懂
interceptor.handleMethodException(targetObject, method, allArguments, method.getParameterTypes(), t);
} catch (Throwable t2) {
LOGGER.error(t2, "class[{}] handle method[{}] exception failure", obj.getClass(), method.getName());
}
throw t;
} finally {
try
// 类似 aop 懂得都懂
ret = interceptor.afterMethod(targetObject, method, allArguments, method.getParameterTypes(), ret);
} catch (Throwable t) {
LOGGER.error(t, "class[{}] after method[{}] intercept failure", obj.getClass(), method.getName());
}
}
return ret;
}
十六、 BootstrapInterRuntimeAssist
16.1 getAgentClassLoader
获取 Agent classloader
为什么要通过当前类的类加载器获取
public static ClassLoader getAgentClassLoader() {
try {
// 当前类的 classloader
ClassLoader loader = Thread.currentThread().getContextClassLoader();
if (loader == null) {
return null;
}
// 找到 AgentClassLoader
Class<?> agentClassLoaderClass = Class.forName(AGENT_CLASSLOADER_DEFAULT, true, loader);
// 找到 DEFAULT_AGENT_CLASSLOADER_INSTANCE AgentClassLoader 的实例
Field defaultLoaderField = agentClassLoaderClass.getDeclaredField(DEFAULT_AGENT_CLASSLOADER_INSTANCE);
defaultLoaderField.setAccessible(true);
ClassLoader defaultAgentClassLoader = (ClassLoader) defaultLoaderField.get(null);
return defaultAgentClassLoader;
} catch (Exception e) {
e.printStackTrace(OUT);
return null;
}
}
16.2 createInterceptor
public static <T> T createInterceptor(ClassLoader defaultAgentClassLoader, String className, IBootstrapLog log) {
try {
// 通过 AgentClassLoader 加载拦截类
Class<?> interceptor = Class.forName(className, true, defaultAgentClassLoader);
return (T) interceptor.newInstance();
} catch (Exception e) {
log.error(e, "Interceptor[{}] not found", className);
}
return null;
}
16.3 getLogger
public static IBootstrapLog getLogger(ClassLoader defaultAgentClassLoader, String interceptor) {
try {
Class<?> logManagerClass = Class.forName(LOG_MANAGER_CLASS, true, defaultAgentClassLoader);
Method getLogger = logManagerClass.getMethod(LOG_MANAGER_GET_LOGGER_METHOD, String.class);
return (IBootstrapLog) getLogger.invoke(null, interceptor + "_internal");
} catch (Exception e) {
e.printStackTrace(OUT);
return null;
}
}
十七、InterceptorInstanceLoader
The InterceptorInstanceLoader
is a classes finder and container. This is a very important class in sky-walking’s auto-instrumentation mechanism. If you want to fully understand why need this, and how it works, you need have knowledge about Classloader appointment mechanism.
这个类是一个 class 的容器与查询器,非常之重要,如果想知道为啥需要这个,如何工作的,建议了解类加载机制
private static ConcurrentHashMap<String, Object> INSTANCE_CACHE = new ConcurrentHashMap<String, Object>();
private static ReentrantLock INSTANCE_LOAD_LOCK = new ReentrantLock();
private static Map<ClassLoader, ClassLoader> EXTEND_PLUGIN_CLASSLOADERS = new HashMap<ClassLoader, ClassLoader>();
17.1 load
加载一个单例的 interceptor 的 实例,为每个要增强目标类的加载器创建一个 AgentClassLoader,并作为其父加载器,可以从 plugins, activations
中加载 interceptor。
/**
* Load an instance of interceptor, and keep it singleton. Create {@link AgentClassLoader} for each
* targetClassLoader, as an extend classloader. It can load interceptor classes from plugins, activations folders.
* // 需要加载的 interceptor 的类名称
* @param className the interceptor class, which is expected to be found
// 增强类的类加载器
* @param targetClassLoader the class loader for current application context
* @param <T> expected type
* @return the type reference.
*/
public static <T> T load(String className,
ClassLoader targetClassLoader) throws IllegalAccessException, InstantiationException, ClassNotFoundException, AgentPackageNotFoundException {
// 没有的话就用当前类的类加载器
if (targetClassLoader == null) {
targetClassLoader = InterceptorInstanceLoader.class.getClassLoader();
}
// 实例的 key 定义为 需要加载的 interceptor 的类名称 + _OF_ + @ + 被增强类的类加载器的哈希
String instanceKey = className + "_OF_" + targetClassLoader.getClass().getName() + "@" + Integer.toHexString(targetClassLoader.hashCode());
// 超找到了,直接返回
Object inst = INSTANCE_CACHE.get(instanceKey);
if (inst == null) {
// 上锁
INSTANCE_LOAD_LOCK.lock();
ClassLoader pluginLoader;
try {
// 找一下被增强类的类加载器,有没有对应的 插件 AgentClassLoader
pluginLoader = EXTEND_PLUGIN_CLASSLOADERS.get(targetClassLoader);
if (pluginLoader == null) {
// 没有的话 new 一个
pluginLoader = new AgentClassLoader(targetClassLoader);
// 并且将 被增强类的类加载器 作为 key, value 为 AgentClassLoader
EXTEND_PLUGIN_CLASSLOADERS.put(targetClassLoader, pluginLoader);
}
} finally {
// 解锁
INSTANCE_LOAD_LOCK.unlock();
}
// 通过 AgentClassLoader 查找下 interceptor
inst = Class.forName(className, true, pluginLoader).newInstance();
if (inst != null) {
INSTANCE_CACHE.put(instanceKey, inst);
}
}
return (T) inst;
}