SkyWalking8.7源码解析(三):静态方法插桩、构造器和实例方法插桩、插件拦截器加载流程、JDK类库插件工作原理

SkyWalking8.7源码解析(三):静态方法插桩、构造器和实例方法插桩、插件拦截器加载流程、JDK类库插件工作原理,第1张

SkyWalking8.7源码解析(三):静态方法插桩、构造器和实例方法插桩、插件拦截器加载流程、JDK类库插件工作原理 10、静态方法插桩

Transform的transform()方法中调用每个插件的define()方法去做字节码增强,AbstractClassEnhancePluginDefine的define()方法中再调用自己的enhance()方法做字节码增强,enhance()方法源码如下:

public abstract class AbstractClassEnhancePluginDefine {

    
    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 enhanceClass(TypeDescription typeDescription, DynamicType.Builder newClassBuilder,
                                                  ClassLoader classLoader) throws PluginException;
  
    
    protected abstract DynamicType.Builder enhanceInstance(TypeDescription typeDescription,
                                                     DynamicType.Builder newClassBuilder, ClassLoader classLoader,
                                                     EnhanceContext context) throws PluginException;  

enhance()方法中先调用enhanceClass()方法做静态方法插桩,再调用enhanceInstance()方法做构造器和实例方法插桩,本节先来看下静态方法插桩

ClassEnhancePluginDefine中实现了AbstractClassEnhancePluginDefine的抽象方法enhanceClass():

public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePluginDefine {

    
    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()) {
                // 是否为JDK类库的类 被Bootstrap ClassLoader加载
                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 {
                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;
    }  

enhanceClass()方法处理逻辑如下:

  1. 获取静态方法拦截点
  2. 根据是否要修改原方法入参和是否为JDK类库的类走不通的分支处理逻辑

获取静态方法拦截点调用的是getStaticMethodsInterceptPoints()方法

public abstract class AbstractClassEnhancePluginDefine {
  
    
    public abstract StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints();  
1)、不修改原方法入参

以mysql-8.x-plugin为例:

public class ConnectionImplCreateInstrumentation extends AbstractMysqlInstrumentation {

    private static final String JDBC_ENHANCE_CLASS = "com.mysql.cj.jdbc.ConnectionImpl";

    private static final String CONNECT_METHOD = "getInstance";

    @Override
    public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {
        return new StaticMethodsInterceptPoint[] {
            new StaticMethodsInterceptPoint() {
                @Override
                public ElementMatcher getMethodsMatcher() {
                    return named(CONNECT_METHOD);
                }

                @Override
                public String getMethodsInterceptor() {
                    return "org.apache.skywalking.apm.plugin.jdbc.mysql.v8.ConnectionCreateInterceptor";
                }

                @Override
                public boolean isOverrideArgs() {
                    return false;
                }
            }
        };
    }

    @Override
    protected ClassMatch enhanceClass() {
        return byName(JDBC_ENHANCE_CLASS);
    }
}

该插件拦截的是ConnectionImpl类中的静态方法getInstance(),不需要修改原方法入参,交给拦截器ConnectionCreateInterceptor来处理

public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePluginDefine {

    
    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()) {
                // 是否为JDK类库的类 被Bootstrap ClassLoader加载
                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 {
                if (isBootstrapInstrumentation()) {
                    newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher()))
                                                     .intercept(MethodDelegation.withDefaultConfiguration()
                                                                                .to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor)));
                } else {
                  	// 1)
                    newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher()))
                                                     .intercept(MethodDelegation.withDefaultConfiguration()
                                                                                .to(new StaticMethodsInter(interceptor)));
                }
            }

        }

        return newClassBuilder;
    }  

mysql-8.x-plugin不需要修改原方法入参,并且拦截的类不是JDK类库的类,所以走的是代码1)处的分支处理逻辑

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

StaticMethodsInter源码如下:

public class StaticMethodsInter {
    private static final ILog LOGGER = LogManager.getLogger(StaticMethodsInter.class);

    
    private String staticMethodsAroundInterceptorClassName;

    
    public StaticMethodsInter(String staticMethodsAroundInterceptorClassName) {
        this.staticMethodsAroundInterceptorClassName = staticMethodsAroundInterceptorClassName;
    }

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

intercept()方法处理逻辑如下:

  1. 实例化自定义的拦截器
  2. 执行beforeMethod()方法
  3. 如果需要执行原方法,执行原方法调用,否则调用_ret()方法
  4. 如果方法执行抛出异常,调用handleMethodException()方法
  5. 最终调用finally中afterMethod()方法
public class MethodInterceptResult {
    private boolean isContinue = true;

    private Object ret = null;

    
    public void defineReturnValue(Object ret) {
        this.isContinue = false;
        this.ret = ret;
    }

    
    public boolean isContinue() {
        return isContinue;
    }

    
    public Object _ret() {
        return ret;
    }
}

这里是否执行原方法默认为true,如果插件的beforeMethod()方法实现中调用了defineReturnValue()传入了返回值,则不会再调用原方法,直接返回传入的返回值

2)、修改原方法入参

允许修改原方法入参会交给StaticMethodsInterWithOverrideArgs去处理

public class StaticMethodsInterWithOverrideArgs {
    private static final ILog LOGGER = LogManager.getLogger(StaticMethodsInterWithOverrideArgs.class);

    
    private String staticMethodsAroundInterceptorClassName;

    
    public StaticMethodsInterWithOverrideArgs(String staticMethodsAroundInterceptorClassName) {
        this.staticMethodsAroundInterceptorClassName = staticMethodsAroundInterceptorClassName;
    }

    
    @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可以修改原方法入参
            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;
    }
}

StaticMethodsInterWithOverrideArgs和StaticMethodsInter的区别在于最后一个入参类型为OverrideCallable

public interface OverrideCallable {
    Object call(Object[] args);
}

插件的beforeMethod()方法实现中会修改原方法入参,然后在原方法的调用时传入修改后的原方法入参

小结:

11、构造器和实例方法插桩

ClassEnhancePluginDefine中实现了AbstractClassEnhancePluginDefine的抽象方法enhanceInstance():

public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePluginDefine {

    
    protected DynamicType.Builder enhanceInstance(TypeDescription typeDescription,
        DynamicType.Builder newClassBuilder, ClassLoader classLoader,
        EnhanceContext context) throws PluginException {
        // 构造器拦截点
        ConstructorInterceptPoint[] constructorInterceptPoints = getConstructorsInterceptPoints();
        // 实例方法拦截点
        InstanceMethodsInterceptPoint[] instanceMethodsInterceptPoints = getInstanceMethodsInterceptPoints();
        String enhanceOriginClassName = typeDescription.getTypeName();
        boolean existedConstructorInterceptPoint = false;
        if (constructorInterceptPoints != null && constructorInterceptPoints.length > 0) {
            existedConstructorInterceptPoint = true;
        }
        boolean existedMethodsInterceptPoints = false;
        if (instanceMethodsInterceptPoints != null && instanceMethodsInterceptPoints.length > 0) {
            existedMethodsInterceptPoints = true;
        }

        
        if (!existedConstructorInterceptPoint && !existedMethodsInterceptPoints) {
            return newClassBuilder;
        }

        
        // 如果当前拦截的类没有实现EnhancedInstance接口
        if (!typeDescription.isAssignableTo(EnhancedInstance.class)) {
            // 没有新增新的字段或者实现新的接口
            if (!context.isObjectExtended()) {
                // 新增一个private volatile的Object类型字段 _$EnhancedClassField_ws
                // 实现EnhancedInstance接口的get/set作为新增字段的get/set方法
                newClassBuilder = newClassBuilder.defineField(
                    CONTEXT_ATTR_NAME, Object.class, ACC_PRIVATE | ACC_VOLATILE)
                                                 .implement(EnhancedInstance.class)
                                                 .intercept(FieldAccessor.ofField(CONTEXT_ATTR_NAME));
                // 将记录状态的上下文EnhanceContext设置为已新增新的字段或者实现新的接口
                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 junction = not(isStatic()).and(instanceMethodsInterceptPoint.getMethodsMatcher());
              	// 如果拦截点为DeclaredInstanceMethodsInterceptPoint
                if (instanceMethodsInterceptPoint instanceof DeclaredInstanceMethodsInterceptPoint) {
                    // 拿到的方法必须是当前类上的 通过注解匹配可能匹配到很多方法不是当前类上的
                    junction = junction.and(ElementMatchers.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;
    }

enhanceInstance()方法处理逻辑如下:

  1. 如果当前拦截的类没有实现EnhancedInstance接口且没有新增新的字段或者实现新的接口,则会新增一个private volatile的Object类型字段_$EnhancedClassField_ws,并实现EnhancedInstance接口的get/set作为新增字段的get/set方法,最后设置标记位,保证该 *** 作只会发生一次
  2. 增强构造器
  3. 增强实例方法
1)、构造器插桩

构造器插桩会交给ConstructorInter去处理

public class ConstructorInter {
    private static final ILog LOGGER = LogManager.getLogger(ConstructorInter.class);

    
    private InstanceConstructorInterceptor interceptor;

    
    public ConstructorInter(String constructorInterceptorClassName, ClassLoader classLoader) throws PluginException {
        try {
            // 实例化自定义的拦截器
            interceptor = InterceptorInstanceLoader.load(constructorInterceptorClassName, classLoader);
        } catch (Throwable t) {
            throw new PluginException("Can't create InstanceConstructorInterceptorV2.", t);
        }
    }

    
    @RuntimeType
    public void intercept(@This Object obj, @AllArguments Object[] allArguments) {
        try {
            EnhancedInstance targetObject = (EnhancedInstance) obj;
            // 在原生构造器执行之后再执行后调用onConstruct()方法
            // 只能访问到EnhancedInstance类型的字段 _$EnhancedClassField_ws
            // 拦截器的onConstruct把某些数据存储到_$EnhancedClassField_ws字段中
            interceptor.onConstruct(targetObject, allArguments);
        } catch (Throwable t) {
            LOGGER.error("ConstructorInter failure.", t);
        }

    }
}

ConstructorInter处理逻辑如下:

  1. 构造函数中实例化自定义的拦截器
  2. intercept()方法中调用拦截器的onConstruct()方法(在原生构造器执行之后再执行后)
public interface InstanceConstructorInterceptor {
    
    void onConstruct(EnhancedInstance objInst, Object[] allArguments) throws Throwable;
}

案例:

以activemq-5.x-plugin为例:

public class ActiveMQProducerInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
    public static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.activemq.ActiveMQProducerInterceptor";
    public static final String ENHANCE_CLASS_PRODUCER = "org.apache.activemq.ActiveMQMessageProducer";
    public static final String CONSTRUCTOR_INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.activemq.ActiveMQProducerConstructorInterceptor";
    public static final String ENHANCE_METHOD = "send";
    public static final String CONSTRUCTOR_INTERCEPT_TYPE = "org.apache.activemq.ActiveMQSession";

    @Override
    public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
        return new ConstructorInterceptPoint[] {
            new ConstructorInterceptPoint() {
                @Override
                public ElementMatcher getConstructorMatcher() {
                    return takesArgumentWithType(0, CONSTRUCTOR_INTERCEPT_TYPE);
                }

                @Override
                public String getConstructorInterceptor() {
                    return CONSTRUCTOR_INTERCEPTOR_CLASS;
                }
            }
        };
    }

该插件拦截的是ActiveMQMessageProducer类中的第一个参数类型为ActiveMQSession的构造器,交给拦截器ActiveMQProducerInterceptor来处理

public class ActiveMQProducerConstructorInterceptor implements InstanceConstructorInterceptor {
    @Override
    public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
        ActiveMQSession session = (ActiveMQSession) allArguments[0];
        // 将broker地址保存到_$EnhancedClassField_ws字段中
        objInst.setSkyWalkingDynamicField(session.getConnection().getTransport().getRemoteAddress().split("//")[1]);
    }
}

所以插件中的构造器插桩是为了在_$EnhancedClassField_ws字段中保存一些数据方便后续使用,这也是ClassEnhancePluginDefine的enhanceInstance()方法中为什么让当前拦截的类新增_$EnhancedClassField_ws字段并实现EnhancedInstance接口的get/set作为新增字段的get/set方法

2)、实例方法插桩
public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePluginDefine {

    
    protected DynamicType.Builder enhanceInstance(TypeDescription typeDescription,
        DynamicType.Builder newClassBuilder, ClassLoader classLoader,
        EnhanceContext context) throws PluginException {
        // 构造器拦截点
        ConstructorInterceptPoint[] constructorInterceptPoints = getConstructorsInterceptPoints();
        // 实例方法拦截点
        InstanceMethodsInterceptPoint[] instanceMethodsInterceptPoints = getInstanceMethodsInterceptPoints();
        String enhanceOriginClassName = typeDescription.getTypeName();
        boolean existedConstructorInterceptPoint = false;
        if (constructorInterceptPoints != null && constructorInterceptPoints.length > 0) {
            existedConstructorInterceptPoint = true;
        }
        boolean existedMethodsInterceptPoints = false;
        if (instanceMethodsInterceptPoints != null && instanceMethodsInterceptPoints.length > 0) {
            existedMethodsInterceptPoints = true;
        }

        
        if (!existedConstructorInterceptPoint && !existedMethodsInterceptPoints) {
            return newClassBuilder;
        }

        
        // 如果当前拦截的类没有实现EnhancedInstance接口
        if (!typeDescription.isAssignableTo(EnhancedInstance.class)) {
            // 没有新增新的字段或者实现新的接口
            if (!context.isObjectExtended()) {
                // 新增一个private volatile的Object类型字段 _$EnhancedClassField_ws
                // 实现EnhancedInstance接口的get/set作为新增字段的get/set方法
                newClassBuilder = newClassBuilder.defineField(
                    CONTEXT_ATTR_NAME, Object.class, ACC_PRIVATE | ACC_VOLATILE)
                                                 .implement(EnhancedInstance.class)
                                                 .intercept(FieldAccessor.ofField(CONTEXT_ATTR_NAME));
                // 将记录状态的上下文EnhanceContext设置为已新增新的字段或者实现新的接口
                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 junction = not(isStatic()).and(instanceMethodsInterceptPoint.getMethodsMatcher());
              	// 1)如果拦截点为DeclaredInstanceMethodsInterceptPoint
                if (instanceMethodsInterceptPoint instanceof DeclaredInstanceMethodsInterceptPoint) {
                    // 拿到的方法必须是当前类上的 通过注解匹配可能匹配到很多方法不是当前类上的
                    junction = junction.and(ElementMatchers.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;
    }

代码1)处判断如果拦截点为DeclaredInstanceMethodsInterceptPoint,会新增匹配条件:拿到的方法必须是当前类上的

public interface DeclaredInstanceMethodsInterceptPoint extends InstanceMethodsInterceptPoint {
}

如果要增强Person的sayHello()方法,那么可以直接通过类名方法名指定,但是如果需要增强所有Controller的方法,需要通过注解指定

通过注解匹配可能匹配到很多方法不是当前类上的,所以判断如果拦截点为DeclaredInstanceMethodsInterceptPoint会新增匹配条件:拿到的方法必须是当前类上的

1)实例方法插桩不修改原方法入参会交给InstMethodsInter去处理

public class InstMethodsInter {
    private static final ILog LOGGER = LogManager.getLogger(InstMethodsInter.class);

    
    private InstanceMethodsAroundInterceptor interceptor;

    
    public InstMethodsInter(String instanceMethodsAroundInterceptorClassName, ClassLoader classLoader) {
        try {
            // 对于同一份字节码,如果由不同的类加载器进行加载,则加载出来的两个实例不相同
            interceptor = InterceptorInstanceLoader.load(instanceMethodsAroundInterceptorClassName, classLoader);
        } catch (Throwable t) {
            throw new PluginException("Can't create InstanceMethodsAroundInterceptor.", t);
        }
    }

    
    @RuntimeType
    public Object intercept(@This Object obj, @AllArguments Object[] allArguments, @SuperCall Callable zuper,
        @Origin Method method) throws Throwable {
        EnhancedInstance targetObject = (EnhancedInstance) obj;

        MethodInterceptResult result = new MethodInterceptResult();
        try {
            interceptor.beforeMethod(targetObject, method, allArguments, method.getParameterTypes(), result);
        } catch (Throwable t) {
            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 {
                interceptor.handleMethodException(targetObject, method, allArguments, method.getParameterTypes(), t);
            } catch (Throwable t2) {
                LOGGER.error(t2, "class[{}] handle method[{}] exception failure", obj.getClass(), method.getName());
            }
            throw t;
        } finally {
            try {
                ret = interceptor.afterMethod(targetObject, method, allArguments, method.getParameterTypes(), ret);
            } catch (Throwable t) {
                LOGGER.error(t, "class[{}] after method[{}] intercept failure", obj.getClass(), method.getName());
            }
        }
        return ret;
    }
}

对于同一份字节码,如果由不同的类加载器进行加载,则加载出来的两个实例不相同,所以在加载拦截器的时候传入了classLoader

2)实例方法插桩修改原方法入参会交给InstMethodsInterWithOverrideArgs去处理

public class InstMethodsInterWithOverrideArgs {
    private static final ILog LOGGER = LogManager.getLogger(InstMethodsInterWithOverrideArgs.class);

    
    private InstanceMethodsAroundInterceptor interceptor;

    
    public InstMethodsInterWithOverrideArgs(String instanceMethodsAroundInterceptorClassName, ClassLoader classLoader) {
        try {
            interceptor = InterceptorInstanceLoader.load(instanceMethodsAroundInterceptorClassName, classLoader);
        } catch (Throwable t) {
            throw new PluginException("Can't create InstanceMethodsAroundInterceptor.", t);
        }
    }

    
    @RuntimeType
    public Object intercept(@This Object obj, @AllArguments Object[] allArguments, @Origin Method method,
        @Morph OverrideCallable zuper) throws Throwable {
        EnhancedInstance targetObject = (EnhancedInstance) obj;

        MethodInterceptResult result = new MethodInterceptResult();
        try {
            interceptor.beforeMethod(targetObject, method, allArguments, method.getParameterTypes(), result);
        } catch (Throwable t) {
            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(allArguments);
            }
        } catch (Throwable t) {
            try {
                interceptor.handleMethodException(targetObject, method, allArguments, method.getParameterTypes(), t);
            } catch (Throwable t2) {
                LOGGER.error(t2, "class[{}] handle method[{}] exception failure", obj.getClass(), method.getName());
            }
            throw t;
        } finally {
            try {
                ret = interceptor.afterMethod(targetObject, method, allArguments, method.getParameterTypes(), ret);
            } catch (Throwable t) {
                LOGGER.error(t, "class[{}] after method[{}] intercept failure", obj.getClass(), method.getName());
            }
        }
        return ret;
    }
}

不修改原方法入参和修改原方法入参的处理逻辑和静态方法插桩的处理逻辑相同

问题1:为什么StaticMethodsInter可以直接通过clazz.getClassLoader()获取类加载器,而InstMethodsInter需要从上层传递ClassLoader

StaticMethodsInter可以直接通过clazz.getClassLoader()获取类加载器是因为静态方法直接绑定了类

InstMethodsInter需要从上层传递ClassLoader有两个原因:第一个是一份字节码可能被多个ClassLoader加载,这样加载出来的每个实例都不相等,所以必须要绑定好ClassLoader。第二个原因是InstMethodsInter里对拦截器的加载前置到了构造方法,这是因为可能出现无法加载拦截器成功的情况,如果放到intercept()方法里去延后加载拦截器,那么拦截器加载失败产生的异常将和字节码修改导致的异常、业务异常出现混乱,这里是为了让异常边界清晰而做的处理

问题2:intercept()方法中通过zuper.call()执行原方法的调用,这里为什么不能替换成method.invoke(clazz.newInstance())

public class StaticMethodsInter {
  
    @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();
//                ret = method.invoke(clazz.newInstance());
            }
        } 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;
    }  

解答这个问题需要借助一个Java实时反编译工具friday,查看挂载SkyWalking Agent之后反编译的内容

@RestController
@RequestMapping("/api/hello")
public class UserController {

    @GetMapping
    public String sayHello() {
        return "hello";
    }

}

UserController反编译的内容:

@RestController
@RequestMapping(value={"/api/hello"})
public class UserController
implements EnhancedInstance {
    private volatile Object _$EnhancedClassField_ws;
    public static volatile  InstMethodsInter delegate$mvblfc0;
    public static volatile  InstMethodsInter delegate$hfbkh30;
    public static volatile  ConstructorInter delegate$gr07501;
    private static final  Method cachedValue$kkbY4FHP$ldstch2;
    public static volatile  InstMethodsInter delegate$lvp69q1;
    public static volatile  InstMethodsInter delegate$mpv7fs0;
    public static volatile  ConstructorInter delegate$v0q1e31;
    private static final  Method cachedValue$Hx3zGNqH$ldstch2;

    public UserController() {
        this(null);
        delegate$v0q1e31.intercept((Object)this, new Object[0]);
    }

    private  UserController(auxiliary.YsFzTfDy ysFzTfDy) {
    }

    @GetMapping
    public String sayHello() {
        return (String)delegate$lvp69q1.intercept((Object)this, new Object[0], (Callable)new auxiliary.pEJy33Ip(this), cachedValue$Hx3zGNqH$ldstch2);
    }

    private  String sayHello$originalVVkKcL() {
        return "hello";
    }

    static {
        ClassLoader.getSystemClassLoader().loadClass("org.apache.skywalking.apm.dependencies.net.bytebuddy.dynamic.Nexus").getMethod("initialize", Class.class, Integer.TYPE).invoke(null, UserController.class, 544534948);
        cachedValue$Hx3zGNqH$ldstch2 = UserController.class.getMethod("sayHello", new Class[0]);
    }

    final  String sayHello$originalVVkKcL$accessor$Hx3zGNqH() {
        return this.sayHello$originalVVkKcL();
    }
}

SkyWalkingAgent的premain()方法中在构建agentBuilder时使用的策略是RETRANSFORMATION

public class SkyWalkingAgent {

    public static void premain(String agentArgs, Instrumentation instrumentation) throws PluginException {
      	// ...
        agentBuilder.type(pluginFinder.buildMatch()) // 指定ByteBuddy要拦截的类
                    .transform(new Transformer(pluginFinder))
                    .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION) // redefine和retransform的区别在于是否保留修改前的内容
                    .with(new RedefinitionListener())
                    .with(new Listener())
                    .installOn(instrumentation);

redefine和retransform的区别在于是否保留修改前的内容,从反编译的内容可以看到sayHello()方法的内容已经被修改掉了,原方法被重命名为sayHello$original$+随机字符串

新的sayHello()方法中调用了InstMethodsInter的intercept()方法,最后传入的intercept()的method参数是被修改后的sayHello()方法,不再指向原生的sayHello()方法,如果在InstMethodsInter使用method.invoke(clazz.newInstance())就相当于自己调自己,就会死递归下去

小结:

12、插件拦截器加载流程

无论是静态方法插桩还是构造器和实例方法插桩都会调用InterceptorInstanceLoader的load()方法来实例化插件拦截器

public class InterceptorInstanceLoader {

    private static ConcurrentHashMap INSTANCE_CACHE = new ConcurrentHashMap();
    private static ReentrantLock INSTANCE_LOAD_LOCK = new ReentrantLock();
    
    private static Map EXTEND_PLUGIN_CLASSLOADERS = new HashMap();

    
    public static  T load(String className,
        ClassLoader targetClassLoader) throws IllegalAccessException, InstantiationException, ClassNotFoundException, AgentPackageNotFoundException {
        if (targetClassLoader == null) {
            targetClassLoader = InterceptorInstanceLoader.class.getClassLoader();
        }
        // org.example.Hello_OF_org.example.classloader.MyClassLoader@xxxxx
        String instanceKey = className + "_OF_" + targetClassLoader.getClass()
                                                                   .getName() + "@" + Integer.toHexString(targetClassLoader
            .hashCode());
        // className所代表的拦截器的实例 对于同一个classloader而言相同的类只加载一次
        Object inst = INSTANCE_CACHE.get(instanceKey);
        if (inst == null) {
            INSTANCE_LOAD_LOCK.lock();
            ClassLoader pluginLoader;
            try {
                pluginLoader = EXTEND_PLUGIN_CLASSLOADERS.get(targetClassLoader);
                if (pluginLoader == null) {
                    // targetClassLoader作为AgentClassLoader的父类加载器
                    pluginLoader = new AgentClassLoader(targetClassLoader);
                    EXTEND_PLUGIN_CLASSLOADERS.put(targetClassLoader, pluginLoader);
                }
            } finally {
                INSTANCE_LOAD_LOCK.unlock();
            }
            // 通过pluginLoader来实例化拦截器对象
            inst = Class.forName(className, true, pluginLoader).newInstance();
            if (inst != null) {
                INSTANCE_CACHE.put(instanceKey, inst);
            }
        }

        return (T) inst;
    }
}

为什么针对不同的targetClassLoader,要初始化多个AgentClassLoader实例,并用targetClassLoader作为AgentClassLoader的parent

如果只实例化一个AgentClassLoader实例,由于应用系统中的类不存在于AgentClassLoader的classpath下,那此时AgentClassLoader加载不到应用系统中的类

针对每个targetClassLoader都初始化一个AgentClassLoader实例,并用targetClassLoader作为AgentClassLoader的父类加载器,通过双亲委派模型模型,targetClassLoader可以加载应用系统中的类

以dubbo插件为例,假设应用系统中Dubbo的类是由AppClassLoader加载的

DubboInterceptor要修改MonitorFilter的字节码,两个类需要能交互,前提就是DubboInterceptor能通过某种方式访问到MonitorFilter

让AgentClassLoader的父类加载器指向加载Dubbo的AppClassLoader,当DubboInterceptor去 *** 作MonitorFilter的时候,通过双亲委派模型模型,AgentClassLoader的父类加载器AppClassLoader能加载到MonitorFilter

13、JDK类库插件工作原理 1)、Agent启动流程:将必要的类注入到Bootstrap ClassLoader
public class SkyWalkingAgent {

    public static void premain(String agentArgs, Instrumentation instrumentation) throws PluginException {
        final PluginFinder pluginFinder;
        try {
            // 初始化配置
            SnifferConfigInitializer.initializeCoreConfig(agentArgs);
        } catch (Exception e) {
            // try to resolve a new logger, and use the new logger to write the error log here
            LogManager.getLogger(SkyWalkingAgent.class)
                    .error(e, "SkyWalking agent initialized failure. Shutting down.");
            return;
        } finally {
            // refresh logger again after initialization finishes
            LOGGER = LogManager.getLogger(SkyWalkingAgent.class);
        }

        try {
            // 加载插件
            pluginFinder = new PluginFinder(new PluginBootstrap().loadPlugins());
        } catch (AgentPackageNotFoundException ape) {
            LOGGER.error(ape, "Locate agent.jar failure. Shutting down.");
            return;
        } catch (Exception e) {
            LOGGER.error(e, "SkyWalking agent initialized failure. Shutting down.");
            return;
        }

        // 定制化Agent行为
        // 创建ByteBuddy实例
        final ByteBuddy byteBuddy = new ByteBuddy().with(Typevalidation.of(Config.Agent.IS_OPEN_DEBUGGING_CLASS));

        // 指定ByteBuddy要忽略的类
        AgentBuilder agentBuilder = new AgentBuilder.Default(byteBuddy).ignore(
                nameStartsWith("net.bytebuddy.")
                        .or(nameStartsWith("org.slf4j."))
                        .or(nameStartsWith("org.groovy."))
                        .or(nameContains("javassist"))
                        .or(nameContains(".asm."))
                        .or(nameContains(".reflectasm."))
                        .or(nameStartsWith("sun.reflect"))
                        .or(allSkyWalkingAgentExcludeToolkit())
                        .or(ElementMatchers.isSynthetic()));

        // 将必要的类注入到Bootstrap ClassLoader
        JDK9ModuleExporter.EdgeClasses edgeClasses = new JDK9ModuleExporter.EdgeClasses();
        try {
            agentBuilder = BootstrapInstrumentBoost.inject(pluginFinder, instrumentation, agentBuilder, edgeClasses);
        } catch (Exception e) {
            LOGGER.error(e, "SkyWalking agent inject bootstrap instrumentation failure. Shutting down.");
            return;
        }

SkyWalkingAgent的premain()方法中会调用BootstrapInstrumentBoost的inject()方法将必要的类注入到Bootstrap ClassLoader,inject()方法源码如下:

public class BootstrapInstrumentBoost {

    public static AgentBuilder inject(PluginFinder pluginFinder, Instrumentation instrumentation,
        AgentBuilder agentBuilder, JDK9ModuleExporter.EdgeClasses edgeClasses) throws PluginException {
        // 所有要注入到Bootstrap ClassLoader里的类
        Map classesTypeMap = new HashMap<>();

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

        
        for (String generatedClass : classesTypeMap.keySet()) {
            edgeClasses.add(generatedClass);
        }

        
        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)处先调用prepareJREInstrumentation(),源码如下:

public class BootstrapInstrumentBoost {

    private static boolean prepareJREInstrumentation(PluginFinder pluginFinder,
        Map classesTypeMap) throws PluginException {
        TypePool typePool = TypePool.Default.of(BootstrapInstrumentBoost.class.getClassLoader());
        // 1)所有要对JDK核心类库生效的插件
        List bootstrapClassMatchDefines = pluginFinder.getBootstrapClassMatchDefine();
        for (AbstractClassEnhancePluginDefine define : bootstrapClassMatchDefines) {
            // 是否定义实例方法拦截点
            if (Objects.nonNull(define.getInstanceMethodsInterceptPoints())) {
                for (InstanceMethodsInterceptPoint point : define.getInstanceMethodsInterceptPoints()) {
                  	// 2)
                    if (point.isOverrideArgs()) {
                        generateDelegator(
                            classesTypeMap, typePool, INSTANCE_METHOD_WITH_OVERRIDE_ARGS_DELEGATE_TEMPLATE, point
                                .getMethodsInterceptor());
                    } else {
                      	// 3)
                        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)处调用pluginFinder的getBootstrapClassMatchDefine()方法,在初始化PluginFinder对象的时候,会对加载的所有插件做分类,要对JDK核心类库生效的插件都放入到一个List(bootstrapClassMatchDefine)中,这里调用getBootstrapClassMatchDefine()就是拿到所有要对JDK核心类库生效的插件

遍历所有要对JDK核心类库生效的插件,分别判断是否定义实例方法拦截点、是否定义构造器拦截点、是否定义静态方法拦截点,以实例方法拦截点为例,代码2)处再根据是否修改原方法入参走不同分支处理逻辑

以不重写原方法入参为例,代码3)处调用generateDelegator()方法生成一个代理器,这里会传入一个模板类名,对于实例方法拦截点且不修改原方法入参,模板类名为org.apache.skywalking.apm.agent.core.plugin.bootstrap.template.InstanceMethodInterTemplate

public class InstanceMethodInterTemplate {
    
    private static String TARGET_INTERCEPTOR;

    private static InstanceMethodsAroundInterceptor INTERCEPTOR;
    private static IBootstrapLog LOGGER;

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

    
    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()方法和实例方法插桩的InstMethodsInter的intercept()方法逻辑基本相同

generateDelegator()方法源码如下:

public class BootstrapInstrumentBoost {

    
    private static void generateDelegator(Map classesTypeMap, TypePool typePool,
        String templateClassName, String methodsInterceptor) {
        // methodsInterceptor + "_internal"
        String internalInterceptorName = internalDelegate(methodsInterceptor);
        try {
            // ClassLoaderA 已经加载了100个类,但是在这个ClassLoader的classpath下有200个类,那么这里
            // typePool.describe可以拿到当前ClassLoader的classpath下还没有加载的类的定义(描述)
            TypeDescription templateTypeDescription = typePool.describe(templateClassName).resolve();

            DynamicType.Unloaded interceptorType = new ByteBuddy().redefine(templateTypeDescription, ClassFileLocator.ForClassLoader
                    .of(BootstrapInstrumentBoost.class.getClassLoader()))
                                                                  // 改名为methodsInterceptor + "_internal"
                                                                  .name(internalInterceptorName)
                                                                  // TARGET_INTERCEPTOR赋值为插件拦截器全类名
                                                                  .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);
        }
    }

generateDelegator()方法就是将模板类交给ByteBuddy去编译成字节码,改了新的类名,并将TARGET_INTERCEPTOR属性赋值为插件拦截器全类名,然后就放入到classesTypeMap中(所有要注入到BootStrapClassLoader中的类)

再回到BootstrapInstrumentBoost的inject()方法:

public class BootstrapInstrumentBoost {

    public static AgentBuilder inject(PluginFinder pluginFinder, Instrumentation instrumentation,
        AgentBuilder agentBuilder, JDK9ModuleExporter.EdgeClasses edgeClasses) throws PluginException {
        // 所有要注入到Bootstrap ClassLoader里的类
        Map classesTypeMap = new HashMap<>();

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

        
        for (String generatedClass : classesTypeMap.keySet()) {
            edgeClasses.add(generatedClass);
        }

        
      	// 2)
        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)处调用prepareJREInstrumentation()方法,核心逻辑:针对于目标类是JDK核心类库的插件,根据插件的拦截点的不同(实例方法、静态方法、构造方法),使用不同的模板(xxxTemplate)来定义新的拦截器的核心处理逻辑,并且将插件本身定义的拦截器的全类名赋值给模板的TARGET_INTERCEPTOR字段

代码2)处将生成的类注入到Bootstrap ClassLoader

2)、JDK类库方法插桩

无论是静态方法插桩还是构造器和实例方法插桩都会判断是否是JDK类库中的类,如果是会调用BootstrapInstrumentBoost的forInternalDelegateClass()方法,以实例方法插桩为例:

public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePluginDefine {
    
    protected DynamicType.Builder enhanceInstance(TypeDescription typeDescription,
        // ...
        
        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 junction = not(isStatic()).and(instanceMethodsInterceptPoint.getMethodsMatcher());
                // 如果拦截点为DeclaredInstanceMethodsInterceptPoint
                if (instanceMethodsInterceptPoint instanceof DeclaredInstanceMethodsInterceptPoint) {
                    // 拿到的方法必须是当前类上的 通过注解匹配可能匹配到很多方法不是当前类上的
                    junction = junction.and(ElementMatchers.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;
    }

BootstrapInstrumentBoost的forInternalDelegateClass()方法源码如下:

public class BootstrapInstrumentBoost {

    public static Class forInternalDelegateClass(String methodsInterceptor) {
        try {
            // methodsInterceptor + "_internal"
            return Class.forName(internalDelegate(methodsInterceptor));
        } catch (ClassNotFoundException e) {
            throw new PluginException(e.getMessage(), e);
        }
    }

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

public class InstanceMethodInterTemplate {
    
    private static String TARGET_INTERCEPTOR;

    private static InstanceMethodsAroundInterceptor INTERCEPTOR;
    private static IBootstrapLog LOGGER;

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

    
    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生成的类去处理,实际也就是模板类InstanceMethodInterTemplate的TARGET_INTERCEPTOR赋值为插件拦截器全类名,和实例方法插桩的InstMethodsInter的intercept()方法相比这里多调用了一个prepare()方法

prepare()方法处理逻辑如下:

  1. 拿到AgentClassLoader
  2. 通过AgentClassLoader加载,拿到ILog生成日志对象
  3. 通过AgentClassLoader加载,拿到插件自定义的拦截器实例

InstanceMethodInterTemplate生成的类是由BootstrapClassLoader去加载的,而日志对象和插件自定义的拦截器都是通过AgentClassLoader去加载的,prepare()方法本质就是为了打通BootstrapClassLoader和AgentClassLoader

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

小结:

参考:

SkyWalking8.7.0源码分析(如果你对SkyWalking Agent源码感兴趣的话,强烈建议看下该教程)

欢迎分享,转载请注明来源:内存溢出

原文地址: http://www.outofmemory.cn/zaji/5695441.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存