• Skywalking流程分析_6(静态方法的增强流程)


    前言

    在上文中,介绍了SkyWalkingAgent.Transformer#transform方法,分析了:

    • 找到对此类匹配的所有插件
    • 设置增强上下文标识
    • 字节码增强 define.define
      • 版本查找,类识别和方法识别
        • finder.exist判断是否存在
      • 真正的字节码增强,this.enhance
        接下来我们就来分析真正的字节码增强逻辑

    this.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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这里分为ClassEnhancePluginDefineClassEnhancePluginDefineV2,逻辑都差不多,我们只分析ClassEnhancePluginDefine即可

    静态方法增强

    ClassEnhancePluginDefine.enhanceClass

    protected 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()) {
                //要增加的类是Bootstrap类加载器加载的
                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 {
                //要增加的类是Bootstrap类加载器加载的
                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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • getStaticMethodsInterceptPoints(),获取静态方法拦截点
    • 通过是否修改原方法入参、要加载的类是否是BootStrapClassLoader加载,来分别执行增强逻辑
    不修改原方法入参
    newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher()))
                                                         .intercept(MethodDelegation.withDefaultConfiguration()
                                                                                    .to(new StaticMethodsInter(interceptor)));
    
    • 1
    • 2
    • 3

    以阿里数据源druid为例,不需要修改方法入参,被拦截的类也不是JDK类库的类,所以直接执行最下面的分支逻辑

    public class DruidDataSourceStatManagerInstrumentation extends ClassStaticMethodsEnhancePluginDefine {
        private static final String ENHANCE_CLASS = "com.alibaba.druid.stat.DruidDataSourceStatManager";
        private static final String ENHANCE_METHOD = "addDataSource";
        private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.druid.v1.PoolingAddDruidDataSourceInterceptor";
    
        @Override
        protected ClassMatch enhanceClass() {
            return byName(ENHANCE_CLASS);
        }
    
        //省略...
    
        @Override
        public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {
            return new StaticMethodsInterceptPoint[]{
                    new StaticMethodsInterceptPoint() {
                        @Override
                        public ElementMatcher<MethodDescription> getMethodsMatcher() {
                            return named(ENHANCE_METHOD).and(takesArguments(Object.class, String.class));
                        }
    
                        @Override
                        public String getMethodsInterceptor() {
                            return INTERCEPTOR_CLASS;
                        }
    
                        @Override
                        public boolean isOverrideArgs() {
                            return false;
                        }
                    }
            };
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    能明确看到是对com.alibaba.druid.stat.DruidDataSourceStatManager中的addDataSource进行增强的

    获取要拦截的增强点后,开始调用bytebuddy提供的API:

    • 指定该方法为静态方法isStatic()
    • 指定方法名staticMethodsInterceptPoint.getMethodsMatcher()
    • 传入interceptor实例交给StaticMethodsInter去处理
    • new StaticMethodsInter(interceptor)去做真正的字节码增强

    下面来分析StaticMethodsInter看看具体是怎么做增强的

    StaticMethodsInter
    public class StaticMethodsInter {
        private static final ILog LOGGER = LogManager.getLogger(StaticMethodsInter.class);
    
        /**
         * A class full name, and instanceof {@link StaticMethodsAroundInterceptor} This name should only stay in {@link
         * String}, the real {@link Class} type will trigger classloader failure. If you want to know more, please check on
         * books about Classloader or Classloader appointment mechanism.
         * 
         * 进行具体增强逻辑的类
         */
        private String staticMethodsAroundInterceptorClassName;
    
        /**
         * Set the name of {@link StaticMethodsInter#staticMethodsAroundInterceptorClassName}
         *
         * @param staticMethodsAroundInterceptorClassName class full name.
         */
        public StaticMethodsInter(String staticMethodsAroundInterceptorClassName) {
            this.staticMethodsAroundInterceptorClassName = staticMethodsAroundInterceptorClassName;
        }
    
        /**
         * Intercept the target static method.
         *
         * @param clazz        target class 要修改的字节码的原生类
         * @param allArguments all method arguments 原方法的入参
         * @param method       method description. 原方法
         * @param zuper        the origin call ref. 原方法的调用
         * @return the return value of target static 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(@Origin Class<?> clazz, @AllArguments Object[] allArguments, @Origin Method method,
            @SuperCall Callable<?> zuper) throws Throwable {
            // 实例化自定义的拦截器
            StaticMethodsAroundInterceptor interceptor = InterceptorInstanceLoader.load(staticMethodsAroundInterceptorClassName, clazz
                .getClassLoader());
    
            MethodInterceptResult result = new MethodInterceptResult();
            try {
                //前置增强
                interceptor.beforeMethod(clazz, method, allArguments, method.getParameterTypes(), result);
            } catch (Throwable t) {
                LOGGER.error(t, "class[{}] before static method[{}] intercept failure", clazz, method.getName());
            }
    
            Object ret = null;
            try {
                //如果设置不再调用,则返回你指定的结果
                if (!result.isContinue()) {
                    ret = result._ret();
                } else {
                    //原方法继续调用
                    ret = zuper.call();
                }
            } catch (Throwable t) {
                try {
                    //异常增强
                    interceptor.handleMethodException(clazz, method, allArguments, method.getParameterTypes(), t);
                } catch (Throwable t2) {
                    LOGGER.error(t2, "class[{}] handle static method[{}] exception failure", clazz, method.getName(), t2.getMessage());
                }
                throw t;
            } finally {
                try {
                    //后置增强
                    ret = interceptor.afterMethod(clazz, method, allArguments, method.getParameterTypes(), ret);
                } catch (Throwable t) {
                    LOGGER.error(t, "class[{}] after static method[{}] intercept failure:{}", clazz, method.getName(), t.getMessage());
                }
            }
            return ret;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77

    intercept方法总结:

    • 加载实例化自定义的拦截器
    • 执行前置增强beforeMethod()方法
    • 如果需要执行原方法,执行原方法调用,否则调用_ret()方法
    • 如果方法执行抛出异常,执行异常增强handleMethodException()方法
    • 在finally执行后置增强afterMethod()方法

    注意看这行

    MethodInterceptResult result = new MethodInterceptResult();
    try {
        //前置增强
        interceptor.beforeMethod(clazz, method, allArguments, method.getParameterTypes(), result);
    } catch (Throwable t) {
        LOGGER.error(t, "class[{}] before static method[{}] intercept failure", clazz, method.getName());
    }
    
    Object ret = null;
    try {
        //如果设置不再调用,则返回你指定的结果
        if (!result.isContinue()) {
            ret = result._ret();
        } else {
            //原方法继续调用
            ret = zuper.call();
        }
    } catch (Throwable t)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    MethodInterceptResult结构

    public class MethodInterceptResult {
        private boolean isContinue = true;
    
        private Object ret = null;
    
        /**
         * define the new return value.
         *
         * @param ret new return value.
         */
        public void defineReturnValue(Object ret) {
            this.isContinue = false;
            this.ret = ret;
        }
    
        /**
         * @return true, will trigger method interceptor({@link InstMethodsInter} and {@link StaticMethodsInter}) to invoke
         * the origin method. Otherwise, not.
         */
        public boolean isContinue() {
            return isContinue;
        }
    
        /**
         * @return the new return value.
         */
        public Object _ret() {
            return ret;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    MethodInterceptResult创建对象result后传入了前置增强beforeMethod中,然后根据result.isContinue()返回的结果判断是否继续调用原方法,也就是说:如果插件的beforeMethod()方法实现中调用了defineReturnValue()传入了返回值,则不会再调用原方法,直接返回传入的返回值

    修改原方法入参
    newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher()))
                         .intercept(MethodDelegation.withDefaultConfiguration()
                                                    .withBinders(Morph.Binder.install(OverrideCallable.class))
                                                    .to(new StaticMethodsInterWithOverrideArgs(interceptor)));
    
    • 1
    • 2
    • 3
    • 4

    获取要拦截的增强点后,开始调用bytebuddy提供的API:

    • 指定该方法为静态方法isStatic()
    • 指定方法名staticMethodsInterceptPoint.getMethodsMatcher()
    • 传入interceptor实例交给StaticMethodsInterWithOverrideArgs去处理
    • new StaticMethodsInterWithOverrideArgs(interceptor)去做真正的字节码增强

    下面来分析StaticMethodsInterWithOverrideArgs看看具体是怎么做增强的

    StaticMethodsInterWithOverrideArgs
    public class StaticMethodsInterWithOverrideArgs {
        private static final ILog LOGGER = LogManager.getLogger(StaticMethodsInterWithOverrideArgs.class);
    
        /**
         * A class full name, and instanceof {@link StaticMethodsAroundInterceptor} This name should only stay in {@link
         * String}, the real {@link Class} type will trigger classloader failure. If you want to know more, please check on
         * books about Classloader or Classloader appointment mechanism.
         */
        private String staticMethodsAroundInterceptorClassName;
    
        /**
         * Set the name of {@link StaticMethodsInterWithOverrideArgs#staticMethodsAroundInterceptorClassName}
         *
         * @param staticMethodsAroundInterceptorClassName class full name.
         */
        public StaticMethodsInterWithOverrideArgs(String staticMethodsAroundInterceptorClassName) {
            this.staticMethodsAroundInterceptorClassName = staticMethodsAroundInterceptorClassName;
        }
    
        /**
         * Intercept the target static method.
         *
         * @param clazz        target class
         * @param allArguments all method arguments
         * @param method       method description.
         * @param zuper        the origin call ref.
         * @return the return value of target static 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(@Origin Class<?> clazz, @AllArguments Object[] allArguments, @Origin Method method,
            @Morph OverrideCallable zuper) throws Throwable {
            StaticMethodsAroundInterceptor interceptor = InterceptorInstanceLoader.load(staticMethodsAroundInterceptorClassName, clazz
                .getClassLoader());
    
            MethodInterceptResult result = new MethodInterceptResult();
            try {
                //beforeMethod可以通过操作allArguments来修改原方法入参
                interceptor.beforeMethod(clazz, method, allArguments, method.getParameterTypes(), result);
            } catch (Throwable t) {
                LOGGER.error(t, "class[{}] before static method[{}] intercept failure", clazz, method.getName());
            }
    
            Object ret = null;
            try {
                if (!result.isContinue()) {
                    ret = result._ret();
                } else {
                    // 原方法的调用时传入修改后的原方法入参
                    ret = zuper.call(allArguments);
                }
            } catch (Throwable t) {
                try {
                    //异常增强
                    interceptor.handleMethodException(clazz, method, allArguments, method.getParameterTypes(), t);
                } catch (Throwable t2) {
                    LOGGER.error(t2, "class[{}] handle static method[{}] exception failure", clazz, method.getName(), t2.getMessage());
                }
                throw t;
            } finally {
                try {
                    //后置增强
                    ret = interceptor.afterMethod(clazz, method, allArguments, method.getParameterTypes(), ret);
                } catch (Throwable t) {
                    LOGGER.error(t, "class[{}] after static method[{}] intercept failure:{}", clazz, method.getName(), t.getMessage());
                }
            }
            return ret;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71

    其实能看到StaticMethodsInter和StaticMethodsInterWithOverrideArgs的区别就在于执行原方法调用是的方法不同:

    Callable<?> zuper
    
    ret = zuper.call();
    
    • 1
    • 2
    • 3
    OverrideCallable zuper
    
    ret = zuper.call(allArguments);
    
    • 1
    • 2
    • 3

    静态方法增强的总结:

    • 不修改原方法入参
      • 要增强的类是JDK的类库(待分析)
      • 要增强的类不是JDK的类库
        • 实例化插件中定义的Interceptor
        • 执行前置增强beforeMethod
        • 执行原方法
        • 如果出现异常,执行异常增强handleMethodException
        • 执行后置增强afterMethod
    • 要修改原方法入参
      • 要增强的类是JDK的类库(待分析)
      • 要增强的类不是JDK的类库
        • 实例化插件中定义的Interceptor
        • 执行前置增强beforeMethod
        • 执行原方法
        • 如果出现异常,执行异常增强handleMethodException
        • 执行后置增强afterMethod

    静态方法的具体增强逻辑我们已经分析完毕,后面的文章会分析构造/实例方法增强,以及JDK类库的类是怎么增强的

  • 相关阅读:
    论环境如何影响我们的一切
    基于Matlab使用雷达和摄像头对公路车辆跟踪仿真(附源码)
    P3613 【深基15.例2】寄包柜题解
    Java版本+企业电子招投标系统源代码+支持二开+招投标系统+中小型企业采购供应商招投标平台
    灾难恢复架构规划要点
    Go语言函数基本概念
    爬虫之反爬思路与解决手段
    快解析内网穿透助力外贸管理行业应对多种挑战
    测试需求平台4-Flask实现API服务入门实战
    设置系统缩放比,适配各分辨率
  • 原文地址:https://blog.csdn.net/guntun8987/article/details/134416633