插件加载流程
入口: PluginBootstrap#loadPlugins
# 处理化 ClassLoader
AgentClassLoader.initDefaultLoader();
PluginResourcesResolver resolver = new PluginResourcesResolver();
# 读取所有 jar 包, 读取 skywalking-plugin.def 文件内容
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 {
// 解析 skywalking-plugin.def 文件内容, 转换为 List<PluginDefine>
// 内容格式 name(插件名称)=defineClass(对应类)
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 {
// 类初始化
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());
}
}
plugins.addAll(DynamicPluginLoader.INSTANCE.load(AgentClassLoader.getDefault()));
return plugins;
扫描所有 jar 包的流程在 AgentClassLoader#findResource 方法中
@Override
protected URL findResource(String name) {
// 获取到 agent plugin 目录下所有的jar包
List<Jar> allJars = getAllJars();
for (Jar jar : allJars) {
JarEntry entry = jar.jarFile.getJarEntry(name);
if (entry != null) {
try {
return new URL("jar:file:" + jar.sourceFile.getAbsolutePath() + "!/" + name);
} catch (MalformedURLException ignored) {
}
}
}
return null;
}
字节码增强
SkyWalkingAgent#premain
// 预处理, 屏蔽包
final ByteBuddy byteBuddy = new ByteBuddy().with(TypeValidation.of(Config.Agent.IS_OPEN_DEBUGGING_CLASS));
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()));
// 应用到 instrumentation
// type 设置匹配
agentBuilder.type(pluginFinder.buildMatch())
// 使用插件对应的类来增强
.transform(new Transformer(pluginFinder))
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
// 设置监听器, 针对完整的增强行为
.with(new RedefinitionListener())
// 针对每个类的监听
.with(new Listener())
.installOn(instrumentation);
调用链
- SkyWalkingAgent.Transformer#transform
for (AbstractClassEnhancePluginDefine define : pluginDefines) {
DynamicType.Builder<?> possibleNewBuilder = define.define(
typeDescription, newBuilder, classLoader, context);
if (possibleNewBuilder != null) {
newBuilder = possibleNewBuilder;
}
}
- AbstractClassEnhancePluginDefine#define
- AbstractClassEnhancePluginDefine#enhance
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;
}
- 类增强 ClassEnhancePluginDefineV2#enhanceClass
# 这里只有其中一段, 就是通过对象增强静态方法
newClassBuilder = newClassBuilder.method(
isStatic()
.and(staticMethodsInterceptV2Point.getMethodsMatcher()))
.intercept(MethodDelegation.withDefaultConfiguration()
.to(new StaticMethodsInterV2WithOverrideArgs(interceptor)));
- 实例增强 ClassEnhancePluginDefineV2#enhanceInstance
ElementMatcher.Junction<MethodDescription> junction = not(isStatic()).and(instanceMethodsInterceptV2Point.getMethodsMatcher());
if (instanceMethodsInterceptV2Point instanceof DeclaredInstanceMethodsInterceptV2Point) {
junction = junction.and(ElementMatchers.<MethodDescription>isDeclaredBy(typeDescription));
}
...
newClassBuilder = newClassBuilder.method(junction)
.intercept(MethodDelegation.withDefaultConfiguration()
.withBinders(Morph.Binder.install(OverrideCallable.class))
.to(new InstMethodsInterV2WithOverrideArgs(interceptor, classLoader)));