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

news2024/11/29 22:40:42

前言

之前的文章详细介绍了关于非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;
}

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

总结

  • 在之前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());
  • 这里会调用generateDelegator方法生成一个代理器
  • 其中的参数INSTANCE_METHOD_DELEGATE_TEMPLATE是一个模版类名来传入
  • 模版名为org.apache.skywalking.apm.agent.core.plugin.bootstrap.template.InstanceMethodInterTemplate,这个是模板不是作为实际的类和对象来调用的

InstanceMethodInterTemplate模板

/**
 * --------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;

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

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

下面来详细分析generateDelegator方法

generateDelegator
/**
 * 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
 * 避免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);
    }
}
  • 此方法是将模板类交给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));

将之前生成模版的方法中,类和字节码的映射的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)));
            }
        }
    }
}

能看到,如果是要增强的类是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";
}

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

/**
 * --------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;

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

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类库的流程相同

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1215741.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WorkPlus移动数字化平台,助力企业全面掌控业务和生态

在移动化的时代&#xff0c;企业面临着将业务和生态纳入数字化平台的挑战。WorkPlus作为一款安全专属的移动数字化平台&#xff0c;成为企业业务和生态全面掌控的有力助手。它如同一艘强大的“航空母舰”&#xff0c;助力企业实现全面发展&#xff0c;从业务到生态&#xff0c;…

(珍藏版)Redis经典面试题32道,吊打面试官!

文章目录 Redis最新2023年面试题高级面试题及附答案解析(4)01、Redis 如何做内存优化&#xff1f;02、Redis 为什么要做 Redis 分区&#xff1f;03、Redis 的删除策略有哪些&#xff0c;怎么结合场景选择删除策略&#xff1f;04、Redis 如何理解事务&#xff1f;05、Redis 如何…

借助拧紧曲线高效管理螺栓装配防错——SunTorque智能扭矩系统

拧紧曲线作为拧紧质量的“晴雨表”&#xff0c;在拧紧过程中&#xff0c;能够实时探知到拧紧状态是否存在异常&#xff0c;并根据曲线特质推测出拧紧过程中遇到了什么样的问题&#xff0c;今天SunTorque智能扭矩系统带您了解拧紧曲线在螺栓装配防错管理中如何发挥作用。 合格的…

【软件测试】接口测试中Post方法怎么测?

GET方法和POST方法传递数据的异同 http请求方法get和post是最常被用到的两个方法&#xff0c;get常用于向服务器请求数据&#xff0c;post常用于提交数据给服务器处理。 GET方法其实也可以传递少量的数据。 但它存在以下问题&#xff1a; 1)GET 方法不包含body&#xff0c;因此…

Unity 2021 LTS / Unity 2022 LTS New Shader Graph Node 参考样本

Shader Graph团队很高兴地宣布发布新的节点参考样本&#xff0c;现在可用于2021 LTS, 2022 LTS和未来的版本。 节点参考样本是超过140个Shader图形资源的集合。您可以将这些图用作参考&#xff0c;以了解每个节点的作用及其工作原理&#xff0c;而不是在项目中使用这些图。每个…

计算机组成原理-总线(学习这一篇就够了!)

目录​​​​​​​ 一、总线概述与结构 1.总线原理&#xff1a; 2.总线分类 &#xff08;1&#xff09;片内总线&#xff1a; &#xff08;2&#xff09;I/O总线&#xff1a; &#xff08;3&#xff09;系统总线&#xff1a; 3.总线的特性 &#xff08;1&#xff09;…

知乎怎么快速涨粉?15个实用方法让你迅速积累粉丝

**一、自我介绍** 大家好&#xff0c;我是知乎上的一个普通用户&#xff0c;我在这篇文章中将会分享一些关于如何涨粉的最实用的方法。我相信&#xff0c;只要你们按照这些方法去做&#xff0c;你们也会像我一样&#xff0c;迅速积累起大量的粉丝。 **二、方法分享** **1. 优…

深度学习之基于Yolov5的车流或人流量密度统计

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 YOLOv5 DeepSort 车流/人流量密度统计介绍YOLOv5DeepSort车流/人流量密度统计 二、功能三、系统四. 总结 一项目简介 YOLOv5 DeepSort 车流/人流量密度统计…

持续集成指南:GitHubAction 自动构建+部署AspNetCore项目

前言 之前研究了使用 GitHub Action 自动构建和发布 nuget 包&#xff1a;开发现代化的.NetCore控制台程序&#xff1a;(4)使用GithubAction自动构建以及发布nuget包 现在更进一步&#xff0c;使用 GitHub Action 在其提供的 runner 里构建 docker 镜像&#xff0c;之后提交到阿…

美联储暂停加息 黄金代理要“笑嘻嘻”?

在11月的议息会议上&#xff0c;美联储再次宣布暂停加息。这是继九月份以后&#xff0c;美联储再次做同样的决定&#xff0c;目前已经实现了2连停。停止加息意味着美元资产的吸引度下降&#xff0c;美元指数将会受压&#xff0c;现货黄金价格因为美元的走弱可能上涨&#xff0c…

晨控CK-FR08读卡器与汇川PLC连接EtherCAT通讯手册

晨控CK-FR08读卡器与汇川PLC连接EtherCAT通讯手册 晨控CK-FR08系列是一款基于射频识别技术的高频RFID标签读卡器&#xff0c;读卡器工作频率为13.56MHZ&#xff0c;支持对I-CODE 2、I-CODE SLI等符合ISO15693国际标准协议格式标签的读取。 读卡器同时支持标准工业通讯协议Eth…

一文讲透IGBT工作原理 | 百能云芯

在实际应用中最流行和最常见的电子元器件是双极结型晶体管 BJT 和 MOS管。 IGBT实物图电路符号图 你可以把 IGBT 看作 BJT 和 MOS 管的融合体&#xff0c;IGBT具有 BJT 的输入特性和 MOS 管的输出特性。与 BJT 或 MOS管相比&#xff0c;绝缘栅双极型晶体管 IGBT 的优势在于它提…

Linux Control Cgroups

无论 Docker 如何进行隔离&#xff0c;无法否认的是我们在当前宿主机中运行的所有容器&#xff0c;它依赖的硬件资源都只是当前机器。 其实启动的每一个容器进程&#xff0c;它本身其实就是当前宿主机的进程之一&#xff0c;那么本质上来说&#xff0c;它也会和宿主机中的其他…

接口测试自动化测试的总结与思考,超详细的~

服务端接口测试介绍 什么是服务端? 一般所说的服务端是指为用户在 APP 或 PC 使用的互联网功能提供数据服务的背后的一切。以天猫精灵智能音箱系列的产品链路为例&#xff0c;服务端便是网关&#xff08;包括网关在内&#xff09;之后的链路。 什么是接口? 官方点说&#…

国内也可以做伦敦金的吗?给你答案

虽然伦敦金是国际市场上的贵金属投资方式&#xff0c;但国内投资者同样有机会参与其中&#xff0c;最简单的方式就是通过香港的持牌平台&#xff0c;在网上开设一个账号&#xff0c;并往其中注入一定的资金之后&#xff0c;就可以展开交易。 国内投资者可以炒伦敦金&#xff0c…

Unittest框架--自动化

Python中方法的传递 参数化 pip install parameterized -i https://pypi.douban.com/simple需求&#xff1a;验证Tpshop登录 # 断言参数化 import time import unittest from parameterized import parameterized from selenium import webdriver from selenium.webdriver.co…

飞书开发学习笔记(七)-添加机器人及发送webhook消息

飞书开发学习笔记(七)-添加机器人及发送webhook消息 一.添加飞书机器人 1.1 添加飞书机器人过程 在群的右上角点击折叠按键…选择 设置 群机器人中选择 添加机器人 选择自定义机器人&#xff0c;通过webhook发送消息 弹出的信息中有webhook地址&#xff0c;选择复制。 安…

【Mysql】关于数据库增删查改的一些在线OJ练习

&#x1f308;欢迎来到Python专栏 &#x1f64b;&#x1f3fe;‍♀️作者介绍&#xff1a;前PLA队员 目前是一名普通本科大三的软件工程专业学生 &#x1f30f;IP坐标&#xff1a;湖北武汉 &#x1f349; 目前技术栈&#xff1a;C/C、Linux系统编程、计算机网络、数据结构、Mys…

YOLOV5部署Android Studio安卓平台NCNN

坑非常多&#xff0c;兄弟们&#xff0c;我已经踩了三天的坑了&#xff0c;我这里部署了官方的yolov5s和我自己训练的yolov5n的模型 下载Android Studio&#xff0c;配置安卓开发环境&#xff0c;这个过程比较漫长。 安装cmake&#xff0c;注意安装的是cmake3.10版本。 根据手机…

世界上最便宜好用的服务器低至 $9.99 / 年

世界上最便宜好用的服务器低至 $9.99 / 年 是一个非常爱搞促销的商家&#xff0c;目前只有一个洛杉矶 DC 机房&#xff0c;每次促销给的流量很足&#xff0c;下面总结的促销套餐&#xff0c;经过测试竟然完美超过甲骨文 1 核 6G 的机器&#xff0c;不仅仅 io 完胜&#xff0c;而…