IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> skywalking源码分析第十四篇一agent插件增强实现 -> 正文阅读

[大数据]skywalking源码分析第十四篇一agent插件增强实现

原理图

  • 采用模板方法设计模式定义插件增强逻辑
  • 处理见证者机制
  • 完成静态方法增强逻辑[允许修改参数]
  • 完成构造方法增强逻辑[构造方法调用后增强,不可修改参数]
  • 完成实例方法增强逻辑[允许修改参数]

类层次结构:
AbstractClassEnhancePluginDefine定义插件的方法模板
ClassEnhancePluginDefine负责结合bytebuddy完成增强实现
ClassStaticMethodsEnhancePluginDefine完成静态方法插件定义
ClassInstanceMethodsEnhancePluginDefine完成构造和实例方法插件定义在这里插入图片描述

见证者逻辑

使用场景
当被拦截代码存在多版本,比如mysql-5.x-plugin和mysql-8.x-plugin,比如mysql8存在com.mysql.cj.interceptors.QueryInterceptor,则此时拦截如Statement.execute时,使用QueryInterceptor作为见证者,此时mysql-8.x-plugin只对mysql8的jdbc版本生效,对5,x的版本不生效【因为5.x的jdbc无QueryInterceptor类】,这就是见证者机制使用场景

插件增强原理图

在这里插入图片描述

源码分析一AbstractClassEnhancePluginDefine.define

  • 处理见证者机制
  • 完成目标类插桩增强

 public DynamicType.Builder<?> define(TypeDescription typeDescription,
                                         DynamicType.Builder<?> builder, ClassLoader classLoader, EnhanceContext context) throws PluginException {
    ......闪出其他代码
    见证者:对框架不同版本的处理方式,如果见证者不存在则不进行增强
    String[] witnessClasses = witnessClasses();
    if (witnessClasses != null) {
        for (String witnessClass : witnessClasses) {
            通过classloader对应的类型池判断见证者类在不在
            if (!WitnessClassFinder.INSTANCE.exist(witnessClass, classLoader)) {
                return null;
            }
        }
    }
    真正的增强逻辑 处理静态,构造和实例方法
    DynamicType.Builder<?> newClassBuilder = this.enhance(typeDescription, builder, classLoader, context);
     ......闪出其他代码
    return newClassBuilder;
}

源码分析一ClassEnhancePluginDefine.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;
}

源码分析一enhanceClass

  • 与bytebuddy结合实现静态方法增强
  • 如果覆盖参数使用bytebuddy工具api[Morph.Binder.install(OverrideCallable.class)]
  • 区分是否boot插件,boot插件一般定义在bootstrap-plugins目录下

 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();
        ...... 删除其他代码
        StaticMethodsInterWithOverrideArgs 处理
        if (staticMethodsInterceptPoint.isOverrideArgs()) {
            if (isBootstrapInstrumentation()) {
                getMethodsMatcher 拦截的方法
                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)
                            )
                            增强交给inter进行 结合了bytebuddy的注解[参见bytebuddy]
                            .to(new StaticMethodsInterWithOverrideArgs(interceptor))
                    );
            }
        StaticMethodsInter处理
        } 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;
}

源码分析一enhanceInstance

  • 为被增强类实现EnhancedInstance接口并添加_$EnhancedClassField_ws属性
  • 与bytebuddy结合处理构造方法[不支持覆盖参数,因为构造方法调用完成后调用拦截逻辑]
  • 与bytebuddy结合处理实例方法[区分是否boot插件以及是否可以覆盖参数]

private DynamicType.Builder<?> enhanceInstance(TypeDescription typeDescription,
        DynamicType.Builder<?> newClassBuilder, ClassLoader classLoader,
        EnhanceContext context) throws PluginException {
    ...... 删除大量代码
    所有代理类均有一个_$EnhancedClassField_ws属性
    if (!context.isObjectExtended()) {
        newClassBuilder = newClassBuilder.defineField(CONTEXT_ATTR_NAME, Object.class, ACC_PRIVATE | ACC_VOLATILE)
            .implement(EnhancedInstance.class)
            .intercept(FieldAccessor.ofField(CONTEXT_ATTR_NAME));
        context.extendObjectCompleted();
    }

    
    增强构造方法
    if (existedConstructorInterceptPoint) {
        for (ConstructorInterceptPoint constructorInterceptPoint : constructorInterceptPoints) {
            if (isBootstrapInstrumentation()) {
                newClassBuilder = newClassBuilder.constructor(constructorInterceptPoint.getConstructorMatcher()).intercept(SuperMethodCall.INSTANCE
                    .andThen(MethodDelegation.withDefaultConfiguration()
                        .to(BootstrapInstrumentBoost.forInternalDelegateClass(constructorInterceptPoint.getConstructorInterceptor()))
                    )
                );
            } else {
                newClassBuilder = newClassBuilder.constructor(constructorInterceptPoint.getConstructorMatcher()).intercept(SuperMethodCall.INSTANCE
                    .andThen(MethodDelegation.withDefaultConfiguration()
                        .to(new ConstructorInter(constructorInterceptPoint.getConstructorInterceptor(), classLoader))
                    )
                );
            }
        }
    }

    增强实例方法
    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.<MethodDescription>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)
                                    )
                                    .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;
}

总结

  • 增强类都有一个属性和一个接口实现: _$EnhancedClassField_ws与EnhancedInstance
  • 增强类存在见证者机制witnessClasses,用来区分源码版本
  • 构造方法增强部分的执行逻辑,发生在构造方法被调用后,所以不支持覆盖参数
  • 字节码插桩的实现借助了bytebuddy工具
  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-03-08 22:34:18  更:2022-03-08 22:37:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 9:17:25-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码