SkyWalking源码-- Agent 插件工作原理

498 阅读3分钟

本文基于 SkyWalking-Java-agent 8.15.0 版本

image.png

AbstractClassEnhancePluginDefine:所有插件的基础抽象类。它提供增强类的框架,需要了解更多增强信息可以查看 ClassEnhancePluginDefine

/**  
* witness机制校验当前插件是否可用  
* 调用enhance()方法进行字节码增强流程  
* 将记录状态的上下文EnhanceContext设置为已增强  
*  
* 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);  
    // witness机制校验当前插件是否可用  
    WitnessFinder finder = WitnessFinder.INSTANCE;  
    /**  
    * find witness classes for enhance class  
    */  
    String[] witnessClasses = witnessClasses();  
    if (witnessClasses != null) {  
        for (String witnessClass : witnessClasses) {  
            // 代码1)判断 witnessClass 是否存在  
            if (!finder.exist(witnessClass, classLoader)) {  
                LOGGER.warn("enhance class {} by plugin {} is not activated. Witness class {} does not exist.", transformClassName, interceptorDefineClassName, witnessClass);  
                return null;  
            }  
        }  
    }  
    List<WitnessMethod> witnessMethods = witnessMethods();  
    if (!CollectionUtil.isEmpty(witnessMethods)) {  
        for (WitnessMethod witnessMethod : witnessMethods) {  
            // 代码2)判断 witnessMethod 是否存在  
            if (!finder.exist(witnessMethod, classLoader)) {  
                LOGGER.warn("enhance class {} by plugin {} is not activated. Witness method {} does not exist.", transformClassName, interceptorDefineClassName, witnessMethod);  
                return null;  
            }  
        }  
    }  

    /**  
    * 字节码增强流程  
    * find origin class source code for interceptor  
    */  
    DynamicType.Builder<?> newClassBuilder = this.enhance(typeDescription, builder, classLoader, context);  

    // 将记录状态的上下文EnhanceContext设置为已增强  
    context.initializationStageCompleted();  
    LOGGER.debug("enhance class {} by {} completely.", transformClassName, interceptorDefineClassName);  

    return newClassBuilder;  
}

类增强操作:

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;  
}

protected abstract DynamicType.Builder<?> enhanceInstance(TypeDescription typeDescription,  
                                                        DynamicType.Builder<?> newClassBuilder, ClassLoader classLoader,  
                                                        EnhanceContext context) throws PluginException;

/**  
* 静态方法插桩  
* 1、获取静态方法拦截点  
* 2、根据是否要修改原方法入参和是否为JDK类库的类走不通的分支处理逻辑
*/
protected abstract DynamicType.Builder<?> enhanceClass(TypeDescription typeDescription, DynamicType.Builder<?> newClassBuilder,  
                                                        ClassLoader classLoader) throws PluginException;

Witness 机制

作用:识别组件版本

  • witnessClasses:在指定类加载器下查找指定的类,如果有多个类则必须同时存在
  • witnessMethods:在指定类加载器下查找指定的方法,如果有多个方法则必须同时存在

工作流程

校验 TypeDescription 的合法性

witness 机制校验当前插件是否可用

字节码增强流程

静态方法

  1. 要修改原方法入参
  • 是JDK类库的类
  • 不是JDK类库的类
    • 实例化插件中定义的 Interceptor
    • 调用 beforeMethod()
    • 调用原方法
      • 调用时可以传参
      • 对于异常,调用 handlerMethodException()
    • 调用 afterMethod()
  1. 不修改原方法入参
  • 是JDK类库的类
    • 前置工作:使用对应的 Template 生成实际使用的拦截逻辑,即 Xxx_internal
    • 调用 prepare()
      • 打通 BootstrapClassLoader 和 AgentClassLoader
      • 通过AgentClassLoader加载,拿到日志对象 ILog
      • 通过AgentClassLoader加载,实例化插件定义的拦截器
    • 后续流程和非 JDK 核心类库处理流程一致
  • 不是JDK类库的类
    • 实例化插件中定义的 Interceptor
    • 调用 beforeMethod()
    • 调用原方法
      • 调用时不能传参
      • 对于异常,调用 handlerMethodException()
    • 调用 afterMethod()

构造器和实例方法

  1. 构造器
  • 是JDK类库的类
  • 不是JDK类库的类
    • 只能在拦截的构造器原本逻辑执行完以后再执行 onConstruct
  1. 实例方法(参照静态方法)

将记录状态的上下文 EnhanceContext 设置为已增强