• Skywalking流程分析_9(JDK类库中增强流程)


    前言

    之前的文章详细介绍了关于非JDK类库的静态方法、构造方法、实例方法的增强拦截流程,本文会详细分析JDK类库中的类是如何被增强拦截的

    回到最开始的SkyWalkingAgent#premain

    try {
        /*
        * 里面有个重点逻辑 把一些类注入到Boostrap类加载器中 为了解决Bootstrap类加载器不能访问App类加载器中的内容的问题
        * */
        agentBuilder = BootstrapInstrumentBoost.inject(pluginFinder, instrumentation, agentBuilder, edgeClasses);
    } catch (Exception e) {
        LOGGER.error(e, "SkyWalking agent inject bootstrap instrumentation failure. Shutting down.");
        return;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    BootstrapInstrumentBoost.inject

    这里是将必要的类注入到Bootstrap ClassLoader

    public static AgentBuilder inject(PluginFinder pluginFinder, Instrumentation instrumentation,
        AgentBuilder agentBuilder, JDK9ModuleExporter.EdgeClasses edgeClasses) throws PluginException {
        //所有要注入到 Bootstrap ClassLoader 里的类
        Map<String, byte[]> classesTypeMap = new LinkedHashMap<>();
        //针对于目标类是JDK核心类库的插件,这里根据插件的拦截点的不同(实例方法、静态方法、构造方法)
        //使用不同的模板(XxxTemplate)来定义新的拦截器的核心处理逻辑,并且将插件本身定义的拦截器的全类名赋值给模板的
        //TARGET_INTERCEPTOR字段。 最后,这些新的拦截器的核心处理逻辑都会被放入 Bootstrap ClassLoader 中
        if (!prepareJREInstrumentation(pluginFinder, classesTypeMap)) {
            return agentBuilder;
        }
    
        if (!prepareJREInstrumentationV2(pluginFinder, classesTypeMap)) {
            return agentBuilder;
        }
    
        for (String highPriorityClass : HIGH_PRIORITY_CLASSES) {
            loadHighPriorityClass(classesTypeMap, highPriorityClass);
        }
        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.
         */
        /**
         * 把一些类注入到Boostrap类加载器中 为了解决Bootstrap类加载器不能访问App类加载器中的内容的问题
         * */
        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;
    }
    
    • 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
    BootstrapInstrumentBoost#prepareJREInstrumentation
    private static boolean prepareJREInstrumentation(PluginFinder pluginFinder,
        Map<String, byte[]> classesTypeMap) throws PluginException {
        TypePool typePool = TypePool.Default.of(BootstrapInstrumentBoost.class.getClassLoader());
        // 所有要对JDK核心类库生效的插件
        List<AbstractClassEnhancePluginDefine> bootstrapClassMatchDefines = pluginFinder.getBootstrapClassMatchDefine();
        for (AbstractClassEnhancePluginDefine define : bootstrapClassMatchDefines) {
            // 是否定义实例方法拦截点
            if (Objects.nonNull(define.getInstanceMethodsInterceptPoints())) {
                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());
                    }
                }
            }
            // 是否定义构造器拦截点
            if (Objects.nonNull(define.getConstructorsInterceptPoints())) {
                for (ConstructorInterceptPoint point : define.getConstructorsInterceptPoints()) {
                    generateDelegator(
                        classesTypeMap, typePool, CONSTRUCTOR_DELEGATE_TEMPLATE, point.getConstructorInterceptor());
                }
            }
            // 是否定义静态方法拦截点
            if (Objects.nonNull(define.getStaticMethodsInterceptPoints())) {
                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;
    }
    
    • 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

    总结

    • 在之前PluginFinder对象初始化时就会将加载的所有插件做分类,要对JDK核心类库生效的插件都放入到bootstrapClassMatchDefine集合中,然后调用getBootstrapClassMatchDefine()就是拿到所有要对JDK核心类库生效的插件
    • 循环所有要对JDK核心类库生效的插件,分别判断是否定义实例方法拦截点、是否定义构造器拦截点、是否定义静态方法拦截点
    下面我们来进入实例方法的增强,并不重写原方法为例来分析详细的流程
    private static String INSTANCE_METHOD_DELEGATE_TEMPLATE = "org.apache.skywalking.apm.agent.core.plugin.bootstrap.template.InstanceMethodInterTemplate";
    
    generateDelegator(
        classesTypeMap, typePool, INSTANCE_METHOD_DELEGATE_TEMPLATE, point.getMethodsInterceptor());
    
    • 1
    • 2
    • 3
    • 4
    • 这里会调用generateDelegator方法生成一个代理器
    • 其中的参数INSTANCE_METHOD_DELEGATE_TEMPLATE是一个模版类名来传入
    • 模版名为org.apache.skywalking.apm.agent.core.plugin.bootstrap.template.InstanceMethodInterTemplate,这个是模板不是作为实际的类和对象来调用的

    InstanceMethodInterTemplate模板

    /**
     * --------CLASS TEMPLATE---------
     * 

    Author, Wu Sheng

    *

    Comment, don't change this unless you are 100% sure the agent core mechanism for bootstrap class * instrumentation.

    *

    Date, 24th July 2019

    * ------------------------------- *

    * 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; 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. * - 让BootstrapClassLoader 和 AgentClassloader能够相通 * - 获取到ILog生成日志对象 * - 获取到插件自定义的拦截器增强类实例 * - 替代非JDK核心类库插件运行逻辑里的interceptor = InterceptorInstanceLoader.load(instanceMethodsAroundInterceptorClassName, classLoader); */ private static void prepare() { if (INTERCEPTOR == null) { ClassLoader loader = BootstrapInterRuntimeAssist.getAgentClassLoader(); if (loader != null) { IBootstrapLog logger = BootstrapInterRuntimeAssist.getLogger(loader, TARGET_INTERCEPTOR); if (logger != null) { LOGGER = logger; INTERCEPTOR = BootstrapInterRuntimeAssist.createInterceptor(loader, TARGET_INTERCEPTOR, LOGGER); } } else { LOGGER.error("Runtime ClassLoader not found when create {}." + TARGET_INTERCEPTOR); } } } }

    • 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
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107

    能看出这个模板类intercept()方法和实例方法中非jdk类库增强的intercept()方法里面的逻辑都大致差不多

    下面来详细分析generateDelegator方法

    generateDelegator
    /**
     * Generate the delegator class based on given template class. This is preparation stage level code generation.
     * 根据给定的模板类生成代理器类,这是准备阶段级别的代码生成
     * 

    * One key step to avoid class confliction between AppClassLoader and BootstrapClassLoader * 避免AppClassLoader和BootstrapClassLoader之间的类冲突的一个关键步骤 * * @param classesTypeMap hosts injected binary of generated class 。要注入到Bootstrap类加载器中的类和字节码的映射 * key:全类名 value:字节码 * @param typePool to generate new class 。加载BootstrapInstrumentBoost的ClassLoader的类型池 * @param templateClassName represents the class as template in this generation process. The templates are * pre-defined in SkyWalking agent core。 要进行增强的模板,里面就是环绕增强逻辑的模板 * * @param methodsInterceptor 要进行增强逻辑的拦截增强类 */ private static void generateDelegator(Map<String, byte[]> classesTypeMap, TypePool typePool, String templateClassName, String methodsInterceptor) { //要进行具体增强逻辑的拦截增强类名 + _internal String internalInterceptorName = internalDelegate(methodsInterceptor); try { //某个类加载器 已经加载了10个类,但这个类加载器的classpath下有400个类, //typePool.describe可以获取到这个类加载器的classpath下还没有加载类的描述信息 TypeDescription templateTypeDescription = typePool.describe(templateClassName).resolve(); //把模板通过ByteBuddy编译成字节码 DynamicType.Unloaded interceptorType = new ByteBuddy().redefine(templateTypeDescription, ClassFileLocator.ForClassLoader .of(BootstrapInstrumentBoost.class.getClassLoader())) .name(internalInterceptorName) .field(named("TARGET_INTERCEPTOR")) .value(methodsInterceptor) .make(); classesTypeMap.put(internalInterceptorName, interceptorType.getBytes()); InstrumentDebuggingClass.INSTANCE.log(interceptorType); } catch (Exception e) { throw new PluginException("Generate Dynamic plugin failure", e); } }

    • 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
    • 此方法是将模板类交给ByteBuddy去编译成字节码,改了新的类名,并将TARGET_INTERCEPTOR属性赋值为插件拦截器全类名,然后就放入到classesTypeMap中
    • 此Map是要注入到Bootstrap类加载器中的类和字节码的映射,key:全类名 value:字节码

    接下来回到BootstrapInstrumentBoost.inject(pluginFinder, instrumentation, agentBuilder, edgeClasses)方法,继续分析剩下的部分

    ClassInjector.UsingUnsafe.Factory.resolve(instrumentation)
    /**
     * 把一些必要的类注入到Boostrap类加载器中 为了解决Bootstrap类加载器不能访问App类加载器中的内容的问题
     * */
    ClassInjector.UsingUnsafe.Factory factory = ClassInjector.UsingUnsafe.Factory.resolve(instrumentation);
    factory.make(null, null).injectRaw(classesTypeMap);
    agentBuilder = agentBuilder.with(new AgentBuilder.InjectionStrategy.UsingUnsafe.OfFactory(factory));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    将之前生成模版的方法中,类和字节码的映射的Mapinstrumentation,注入到Bootstrap ClassLoader,此步骤是使用模版进行字节码增强的前提

    JDK类库方法的增强过程

    想让我们回到ClassEnhancePluginDefine#enhanceInstance,再看一下实例方法的在进行增强是的判断逻辑

    if (existedConstructorInterceptPoint) {
        //获取所有构造方法的切点
        for (ConstructorInterceptPoint constructorInterceptPoint : constructorInterceptPoints) {
            //要增加的类是Bootstrap类加载器加载的
            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))));
            }
        }
    }
    
    /**
     * 3. enhance instance methods
     */
    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()) {
                //要增加的类是Bootstrap类加载器加载的
                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 {
                //要增加的类是Bootstrap类加载器加载的
                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)));
                }
            }
        }
    }
    
    • 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

    能看到,如果是要增强的类是JDK类库中的,都是调用到BootstrapInstrumentBoost.forInternalDelegateClass的方法

    BootstrapInstrumentBoost.forInternalDelegateClass

    public static Class forInternalDelegateClass(String methodsInterceptor) {
        try {
            return Class.forName(internalDelegate(methodsInterceptor));
        } catch (ClassNotFoundException e) {
            throw new PluginException(e.getMessage(), e);
        }
    }
    
    public static String internalDelegate(String methodsInterceptor) {
        return methodsInterceptor + "_internal";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    通过Class.forName()加载插件拦截器全类名+_internal的类,这个类在Agent启动流程根据模板类生成并注入到Bootstrap ClassLoader中,所以这里是能加载到,再看一下模版InstanceMethodInterTemplate

    /**
     * --------CLASS TEMPLATE---------
     * 

    Author, Wu Sheng

    *

    Comment, don't change this unless you are 100% sure the agent core mechanism for bootstrap class * instrumentation.

    *

    Date, 24th July 2019

    * ------------------------------- *

    * 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; 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. * - 让BootstrapClassLoader 和 AgentClassloader能够相通 * - 获取到ILog生成日志对象 * - 获取到插件自定义的拦截器增强类实例 * - 替代非JDK核心类库插件运行逻辑里的interceptor = InterceptorInstanceLoader.load(instanceMethodsAroundInterceptorClassName, classLoader); */ private static void prepare() { if (INTERCEPTOR == null) { ClassLoader loader = BootstrapInterRuntimeAssist.getAgentClassLoader(); if (loader != null) { IBootstrapLog logger = BootstrapInterRuntimeAssist.getLogger(loader, TARGET_INTERCEPTOR); if (logger != null) { LOGGER = logger; INTERCEPTOR = BootstrapInterRuntimeAssist.createInterceptor(loader, TARGET_INTERCEPTOR, LOGGER); } } else { LOGGER.error("Runtime ClassLoader not found when create {}." + TARGET_INTERCEPTOR); } } } }

    • 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
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • JDK类库的类做增强会交给模板InstanceMethodInterTemplate生成的类来处理,实际是模板中的TARGET_INTERCEPTOR赋值为插件拦截器全类名
    • 和实例方法插桩的InstMethodsInterintercept()方法相比这里多调用了一个prepare()方法
    • prepare()方法是让BootstrapClassLoader能够和AgentClassLoader相同的关键

    prepare()

    /**
     * Prepare the context. Link to the agent core in AppClassLoader.
     * - 让BootstrapClassLoader 和 AgentClassloader能够相通
     *   - 获取到ILog生成日志对象
     *   - 获取到插件自定义的拦截器增强类实例
     * - 替代非JDK核心类库插件运行逻辑里的interceptor = InterceptorInstanceLoader.load(instanceMethodsAroundInterceptorClassName, classLoader);  
     */
    private static void prepare() {
        if (INTERCEPTOR == null) {
            ClassLoader loader = BootstrapInterRuntimeAssist.getAgentClassLoader();
    
            if (loader != null) {
                IBootstrapLog logger = BootstrapInterRuntimeAssist.getLogger(loader, TARGET_INTERCEPTOR);
                if (logger != null) {
                    LOGGER = logger;
    
                    INTERCEPTOR = BootstrapInterRuntimeAssist.createInterceptor(loader, TARGET_INTERCEPTOR, LOGGER);
                }
            } else {
                LOGGER.error("Runtime ClassLoader not found when create {}." + TARGET_INTERCEPTOR);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    BootstrapInterRuntimeAssist
    public class BootstrapInterRuntimeAssist {
        private static final String AGENT_CLASSLOADER_DEFAULT = "org.apache.skywalking.apm.agent.core.plugin.loader.AgentClassLoader";
        private static final String DEFAULT_AGENT_CLASSLOADER_INSTANCE = "DEFAULT_LOADER";
        private static final String LOG_MANAGER_CLASS = "org.apache.skywalking.apm.agent.core.plugin.bootstrap.BootstrapPluginLogBridge";
        private static final String LOG_MANAGER_GET_LOGGER_METHOD = "getLogger";
        private static final PrintStream OUT = System.out;
    
        public static ClassLoader getAgentClassLoader() {
            try {
                ClassLoader loader = Thread.currentThread().getContextClassLoader();
                if (loader == null) {
                    return null;
                }
                Class<?> agentClassLoaderClass = Class.forName(AGENT_CLASSLOADER_DEFAULT, true, loader);
                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;
            }
        }
    
        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;
            }
        }
    
        public static <T> T createInterceptor(ClassLoader defaultAgentClassLoader, String className, IBootstrapLog log) {
            try {
                Class<?> interceptor = Class.forName(className, true, defaultAgentClassLoader);
                return (T) interceptor.newInstance();
            } catch (Exception e) {
                log.error(e, "Interceptor[{}] not found", className);
            }
            return null;
        }
    }
    
    • 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

    prepare()总结

    • 获取到AgentClassLoader
    • AgentClassLoader加载桥接器BootstrapPluginLogBridge类,然后调用getLogger方法传入TARGET_INTERCEPTOR+_internal得到这个传入的实际类名的BootstrapPluginLogBridge的对象
    • 将得到的BootstrapPluginLogBridge赋给模板类的成员属性LOGGER
    • AgentClassLoader加载插件自定义的拦截器实例

    为什么要用prepare()来特意的利用桥接来绕一下呢

    因为InstanceMethodInterTemplate生成的类是由BootstrapClassLoader去加载的,而日志对象和插件自定义的拦截器都是通过AgentClassLoader去加载的,prepare()方法的作用就是将BootstrapClassLoaderAgentClassLoader能够相同

    举例说明:

    • 如果BootstrapClassLoader加载的由InstanceMethodInterTemplate生成的类是org.apache.skywalking.xxx.HttpClientInterceptor_internalAgentClassLoader加载了日志用到的ILog和插件拦截器HttpClientIntercepotr
    • AgentClassLoader的顶层父类加载器为BootstrapClassLoader,根据双亲委派模型,从下往上加载是可以拿到的,但是从上往下加载是拿不到的,BootstrapClassLoader中不能拿到ILogHttpClientIntercepotr,所以需要通过prepare()方法打通BootstrapClassLoaderAgentClassLoader

    总结

    • 准备工作,使用对应的Template模板来生成实际的拦截增强,实际类名为xxx_internal
    • prepare()方法
      • BootstrapClassLoaderAgentClassLoader能够相通
      • 获取到日志对象ILog
      • 实例化插件定义的拦截器,用来代替非JDK类库增强中的InterceptorInstanceLoader.load(instanceMethodsAroundInterceptorClassName, classLoader)
    • 后续的增强逻辑和非JDK类库的流程相同
  • 相关阅读:
    事件委托代理
    【小余送书第二期】《MLOps工程实践:工具、技术与企业级应用》参与活动,即有机会中奖哦!!!祝各位铁铁们双节快乐!
    Oracle/PLSQL: Atan2 Function
    1016 部分A+B
    Mysql8.0为什么取消了缓存查询的功能
    谷粒商城学习笔记
    暂停Windows更新方法
    设备上架与调试步骤项目篇
    ts视频文件转为mp4(FFmpeg)
    【从零开始学爬虫】采集谷歌网页列表数据
  • 原文地址:https://blog.csdn.net/guntun8987/article/details/134435690