Skyingwalking 源码解读 agent 篇

Skyingwalking 源码解读 agent 篇

文章目录

一、 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

七、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这句话很关键,为什么说是 AppClassLoaderBootstrapClassLoader关键的一步?

个人理解:

​ 增强的原理是修改原原始目标类的字节码,添加相应增强逻辑上去。 当增强 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。

具体而言,该方法的实现步骤如下:

  1. 调用getResolution(witnessClass, classLoader)方法获取到对应的Class文件解析器;
  2. 调用isResolved()方法判断该解析器是否已经解析完成;
  3. 如果已经解析完成,则返回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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值