foreword

This article is the source code learning and sharing of SpringAOP . It is divided into two parts. In the previous article, it is known that after the aspect class of SpringAOP is woven into the business bean , a dynamic proxy object will be generated for the business bean . Notifications are called notification chains. This article will study the entire process of invoking the AOP dynamic proxy object, to explore how the notification method in the aspect, similar to the pre-advice or post-advice, enhances the target method of the target bean .

Note: This article is based on JDK dynamic proxy.

text

1. AOP dynamic proxy object structure analysis

In the example project in the previous article, you can see what the bean IMyService obtained from the container in the test program looks like. The debugging diagram is as follows.

可以看到获取出来的bean实际MyServiceJDK动态代理对象, InvocationHandler JdkDynamicAopProxyJdkDynamicAopProxy中持有ProxyFactory , ProxyFactory holds the target object and notification chain.

Two. AOP dynamic proxy object call analysis

调用动态代理对象的方法时,会调用到InvocationHandlerinvoke()方法,这里InvocationHandler JdkDynamicAopProxy ,所以将JdkDynamicAopProxy The JdkDynamicAopProxy invoke() method is used as the entry to start the analysis.

 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Object oldProxy = null;
    boolean setProxyContext = false;

    TargetSource targetSource = this.advised.targetSource;
    Object target = null;

    try {
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            //不会将通知作用在equals()方法,除非目标对象实现的接口中定义了equals()方法
            return equals(args[0]);
        }
        else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
            //不会将通知作用在hashCode()方法,除非目标对象实现的接口中定义了hashCode()方法
            return hashCode();
        }
        else if (method.getDeclaringClass() == DecoratingProxy.class) {
            return AopProxyUtils.ultimateTargetClass(this.advised);
        }
        else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                method.getDeclaringClass().isAssignableFrom(Advised.class)) {
            //不会将通知作用于Advised接口或者其父接口中定义的方法
            return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
        }

        Object retVal;

        if (this.advised.exposeProxy) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }

        //获取目标对象
        target = targetSource.getTarget();
        //获取目标对象的Class对象
        Class<?> targetClass = (target != null ? target.getClass() : null);

        //将通知链中能够作用于当前方法的通知组装成拦截器链
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

        if (chain.isEmpty()) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            //如果拦截器链是空,那么直接调用目标对象方法
            //AopUtils.invokeJoinpointUsingReflection()最终会调用到method.invoke(target, args)
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        }
        else {
            //创建方法调用器MethodInvocation,实际为ReflectiveMethodInvocation
            //创建ReflectiveMethodInvocation时传入的参数依次为:代理对象,目标对象,目标方法,目标方法参数,目标对象的Class对象,拦截器链
            MethodInvocation invocation =
                    new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            //调用方法调用器的proceed()方法,开始进入调用各个通知方法和目标方法的递归流程
            retVal = invocation.proceed();
        }

        Class<?> returnType = method.getReturnType();
        if (retVal != null && retVal == target &&
                returnType != Object.class && returnType.isInstance(proxy) &&
                !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
            retVal = proxy;
        }
        else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
            throw new AopInvocationException(
                    "Null return value from advice does not match primitive return type for: " + method);
        }
        return retVal;
    }
    finally {
        if (target != null && !targetSource.isStatic()) {
            targetSource.releaseTarget(target);
        }
        if (setProxyContext) {
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}

The above invoke() method mainly does two things. The first thing is to construct all notifications in the notification chain that can act on the current target method into an interceptor chain, and generate method calls based on the interceptor chain. The second thing is to call the ReflectiveMethodInvocation 01f5a2425908dd1bfbbe5b96f9728399 ReflectiveMethodInvocation method of proceed() , this method will call the target method, and in the process of calling, the interceptor chain Interceptors in are also executed to achieve the effect of enhancement. Let's take a look at how the notification chain is constructed into an interceptor chain. this.advised is actually when a dynamic proxy object is generated ProxyFactory , and ProxyFactory is inherited from AdvisedSupport , the way to build a notification chain into an interceptor chain is AdvisedSupport of getInterceptorsAndDynamicInterceptionAdvice() , as shown below.

 public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
    MethodCacheKey cacheKey = new MethodCacheKey(method);
    //先根据Method从缓存中拿拦截器链,缓存中没有时会去生成并缓存起来
    List<Object> cached = this.methodCache.get(cacheKey);
    if (cached == null) {
        //实际调用到DefaultAdvisorChainFactory的getInterceptorsAndDynamicInterceptionAdvice()方法来生成拦截器链
        cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
                this, method, targetClass);
        this.methodCache.put(cacheKey, cached);
    }
    return cached;
}

The interceptor chain corresponding to each target method will be cached after it is generated, so the interceptor chain will be taken from the cache first, and the method of getInterceptorsAndDynamicInterceptionAdvice() DefaultAdvisorChainFactory will be called when it is not in the cache. To generate the interceptor chain, the getInterceptorsAndDynamicInterceptionAdvice() method is implemented as follows.

 public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
        Advised config, Method method, @Nullable Class<?> targetClass) {

    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
    //先从ProxyFactory中将通知链获取出来
    Advisor[] advisors = config.getAdvisors();
    List<Object> interceptorList = new ArrayList<>(advisors.length);
    Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
    Boolean hasIntroductions = null;

    for (Advisor advisor : advisors) {
        //因为Advisor接口有两个子类接口,分别是PointcutAdvisor和IntroductionAdvisor
        if (advisor instanceof PointcutAdvisor) {
            //处理PointcutAdvisor,示例中使用的都是PointcutAdvisor
            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
            if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                //获取切点对象,这里的mm类型为AspectJExpressionPointcut
                MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                boolean match;
                if (mm instanceof IntroductionAwareMethodMatcher) {
                    if (hasIntroductions == null) {
                        hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
                    }
                    //判断当前Advisor是否能够作用于目标方法
                    match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
                }
                else {
                    //判断当前Advisor是否能够作用于目标方法
                    match = mm.matches(method, actualClass);
                }
                if (match) {
                    //如果当前Advisor能够作用于目标方法,那么将当前Advisor转换为MethodInterceptor,即通知转换为方法拦截器
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                    if (mm.isRuntime()) {
                        for (MethodInterceptor interceptor : interceptors) {
                            //将方法拦截器和切点对象封装成InterceptorAndDynamicMethodMatcher并加入拦截器链中
                            interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                        }
                    }
                    else {
                        interceptorList.addAll(Arrays.asList(interceptors));
                    }
                }
            }
        }
        else if (advisor instanceof IntroductionAdvisor) {
            IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
            if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }
        else {
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
        }
    }

    return interceptorList;
}

The process of converting a notification chain to an interceptor chain is outlined below.

  • First get the pointcut object from Advisor , and judge whether the current Advisor can act on the target method according to the pointcut object;
  • Encapsulate the method that can act on the target method Advisor as a method interceptor MethodInterceptor and add it to the interceptor chain.

MethodInterceptor is an interface that defines a method interceptor. The method interceptors corresponding to the pre-notification and post-notification used in the example are MethodBeforeAdviceInterceptor and AspectJAfterAdvice , their relationship can be represented by the following class diagram.

After the interceptor chain is obtained, another method caller ---3a992402438b85f7b192ee5646e522cb--- will be created in the JdkDynamicAopProxy invoke() method of ReflectiveMethodInvocation , and its class diagram is as follows.

From the class diagram, we can know that ReflectiveMethodInvocation holds the proxy object, the target object, the target method, the target method parameters, the Class object of the target object, the interceptor chain, the subsequent call to the notification method and the logic of calling the target method. The entry is the ReflectiveMethodInvocation proceed() method of ---1c2df0aa365286ed3cf2350758b194e4---.

When the AOP dynamic proxy object invocation is analyzed above, the first thing done in the JdkDynamicAopProxy invoke() method of ---131463088e49cf8c336c7f1b8a6a96ed--- is to construct all notifications in the notification chain that can act on the current target method into interception The interceptor chain, and based on the interceptor chain to generate a method caller ReflectiveMethodInvocation , the second thing is analyzed below, that is, the proceed() method that calls ReflectiveMethodInvocation proceed() ReflectiveMethodInvocation can apply the notification enhancement to the target method before and after calling the target method. Let's analyze the whole calling proceed() .

 //currentInterceptorIndex用于指示当前需要调用的拦截器
//初始为-1,每次使用前会先加1
private int currentInterceptorIndex = -1;

public Object proceed() throws Throwable {
    //当拦截器都遍历完后,则调用目标方法
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        //调用invokeJoinpoint()方法来执行目标方法
        //invokeJoinpoint()会调用AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments),即通过反射执行目标方法
        return invokeJoinpoint();
    }

    //把拦截器获取出来
    Object interceptorOrInterceptionAdvice =
            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
        InterceptorAndDynamicMethodMatcher dm =
                (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
        Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
        if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
            //调用各种通知对应的拦截器的invoke()方法
            return dm.interceptor.invoke(this);
        }
        else {
            return proceed();
        }
    }
    else {
        //拦截器是ExposeInvocationInterceptor时会调用到这里
        //ExposeInvocationInterceptor的invoke()方法会先为当前线程保存方法调用器ReflectiveMethodInvocation
        //然后再递归调用ReflectiveMethodInvocation的proceed()方法
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

In the ---89c8d5935bc8cfe4e778e9a803ea7831--- method of ReflectiveMethodInvocation , the --- invoke() proceed() method of all interceptors will be called first, and then the line target method will be called last, but in reality, there are some The notification needs to be executed after the target method is executed or when the target method throws an exception, so it can be speculated that the invoke() method that calls the interceptor does not mean that the notification logic corresponding to the interceptor will be executed, and the interceptor will be executed. The invoke() method of the device will recursively call back the ReflectiveMethodInvocation fbe4f5b46f6f6099e6520394a6b4c58a proceed() method at a certain point in time. For the convenience of understanding, the following three interceptors used in this example, ExposeInvocationInterceptor , MethodBeforeAdviceInterceptor and AspectJAfterAdvice are used for description.

  • The ExposeInvocationInterceptor invoke() is shown below.
 public Object invoke(MethodInvocation mi) throws Throwable {
    MethodInvocation oldInvocation = invocation.get();
    //为当前线程保存方法调用器,即保存ReflectiveMethodInvocation
    invocation.set(mi);
    try {
        //递归调用ReflectiveMethodInvocation的proceed()方法来执行其它拦截器或者目标方法
        return mi.proceed();
    }
    finally {
        invocation.set(oldInvocation);
    }
}

ExposeInvocationInterceptor just saves a reference to the method caller for the current thread.

  • The MethodBeforeAdviceInterceptor invoke() is shown below.
 public Object invoke(MethodInvocation mi) throws Throwable {
    //前置通知的逻辑要先于目标方法执行,所以这里先执行前置通知的逻辑
    this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
    //递归调用ReflectiveMethodInvocation的proceed()方法来执行其它拦截器或者目标方法
    return mi.proceed();
}

As long as the MethodBeforeAdviceInterceptor invoke() method of ---3e896aa5f272c1be81d5edec36087ae1--- is called, the corresponding pre-notification logic will be executed, which is consistent with the pre-notification being executed before the target method is executed, and the pre-notification logic After the execution is completed, the proceed() method of ---84b6b7b89a92873a2a0763a2c4c7525d ReflectiveMethodInvocation will be called back to call other interceptors and target methods.

  • The AspectJAfterAdvice invoke() is shown below.
 public Object invoke(MethodInvocation mi) throws Throwable {
    try {
        //递归调用ReflectiveMethodInvocation的proceed()方法来先执行其它拦截器或者目标方法
        return mi.proceed();
    }
    finally {
        //后置通知的逻辑要在目标方法执行后再执行,所以这里将后置通知的执行放在了finally中
        //也表明就算目标方法或者其它拦截器执行时抛出异常,后置通知的逻辑也是会执行到的
        invokeAdviceMethod(getJoinPointMatch(), null, null);
    }
}

In the AspectJAfterAdvice invoke() method of ---be14a66f73aaa9c31bc1fc086dcd798a---, the invocation of the post-notification logic is placed in finally , so the post-notification logic will be executed after other notifications and target methods are executed.

So here, the method caller ReflectiveMethodInvocation the process of calling the interceptor and the target method has formed a closed loop. With the feature of recursive call, both the target method and the interceptor will be called, although the call of the target method will After all interceptor calls, but the execution of the target method will precede the execution of some advice (such as post advice).

Finally, it should be noted that in the ReflectiveMethodInvocation proceed() method of ---cd665819ad82bdd49bd3e6c679cc5209---, the currentInterceptorIndex field is used to identify the number of interceptors that are currently called. The initial value is -1. Add 1 (ie ++currentInterceptorIndex ), then the position of the interceptor in the collection will actually affect the calling order of the interceptor invoke() method, then through the above source code analysis, the impact of this calling order can be summarized as follows.

  • The position of the interceptors corresponding to different notifications in the collection will not affect the calling sequence of different notifications. For example, the execution of the pre-notification logic will definitely precede the execution of the post-notification logic;
  • The position of the interceptor corresponding to the same notification in the collection will affect the calling sequence of the same notification. For example, the index of the pre-notification 1 in the collection is smaller than the index of the pre-notification 2 in the collection, then the logic of the pre-notification 1 is executed. will precede advance notice 2.

3. Timing diagram

When the AOP dynamic proxy object executes the method, the call sequence diagram is as follows.

Summarize

The dynamic proxy object of SpringAOP holds the notification chain and the target object, then when calling the dynamic proxy object method, it will first find the Advisor that can act on the target method from the notification chain, and then put each eligible The Advisor is encapsulated into MethodInvocation and added to the collection, called the collection of MethodInvocation as the interceptor chain. After getting the interceptor chain, the method will be created based on the interceptor chain. MethodInvocation , and then call the interceptor and target method logic through the MethodInvocation proceed() method of ---40c6c80acf0422b7d75b7d59ff4f8125---.


半夏之沫
65 声望32 粉丝