Spring Aop Annotation Source

Keywords: Spring

Analysis paste

https://blog.csdn.net/jy02268879/article/details/88409710

https://www.cnblogs.com/nullllun/p/9222627.html

 

Summary

In the Bean initialization phase, Spring generates proxy objects for beans. A bean object corresponds to a proxy object. advisors:List of proxy objects stores all scanned AOP notification method (Advisor) information related to bean.class. Each notification method holds its own matching results (yes\no) with all the methods in bean.class. When the call chain is generated for the proxy method, the advisors:List in the current proxy object is traversed, and the results are matched by each AOP notification method to determine whether an AOP notification method joins the call chain.

Matching process: aopProxy (bean) - > dynamic Advised Intercepto - > advised - > traversal notification method advisors [i] - > pointcut. shadowMatchCache - > shadowMatchImpl. match (yes/no)

Creating proxy objects

Order of notification methods

Spraop sorts all Advisors and generates dynamic proxies when Annotation Aware Aspect JAuto Proxy Creator processes bean s to find adapted Advisors. The sortAdvisors method of AspectJAware Advisor AutoProxyCreator

@Override
    @SuppressWarnings("unchecked")
    protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
        List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors =
                new ArrayList<PartiallyComparableAdvisorHolder>(advisors.size());

        //Traversing advisors into partially Comparable Advisors 
        for (Advisor element : advisors) {
            partiallyComparableAdvisors.add(
                    new PartiallyComparableAdvisorHolder(element, DEFAULT_PRECEDENCE_COMPARATOR));  //Default comparator
        }

        //Sort partially Comparable Advisors
        List<PartiallyComparableAdvisorHolder> sorted = PartialOrder.sort(partiallyComparableAdvisors);
        if (sorted != null) {
            List<Advisor> result = new ArrayList<Advisor>(advisors.size());

            //After traversing the sorted partially Comparable Advisors, take out the Advisor and save it in the result 
            for (PartiallyComparableAdvisorHolder pcAdvisor : sorted) {
                result.add(pcAdvisor.getAdvisor());
            }
            return result;
        }
        else {
            //Direct Sorting advisors
            return super.sortAdvisors(advisors);
        }
    }

The order values obtained by each Advisor are sorted from small to large. The rules for obtaining order values are as follows:

  1. First of all, it is judged whether the current Advisor's section class implements the org. spring framework. core. Ordered interface. If yes, it is obtained by calling the getOrder method.
  2. Otherwise, determine whether the current Advisor's facet class contains the org.springframework.core.annotation.Order annotation, if yes, get it from the annotation.
  3. No value was fetched. The default is the lowest priority and the value is the maximum Int.

From the sorting code, there are the following processes:

  1. Annotations to org. spring framework. core. annotation. Order typed on the Advice method are not recognized
  2. If there are more than one Advisor in a facet class, it will be declared in the order of Advice method declaration. The declaration has higher priority than the previous one, and then it will be executed first.
  3. If the order value is the same for different slice classes, the order is sorted according to the order in which spring obtains the slice bean s, and the acquisition is executed first.

 

 

Call procedure

Agent class structure

CGLIB Proxy Object: One-to-one with Bean Object. The interceptor and dispatcher associated with the proxy bean are stored in the proxy object

aopProxy.dynamicAdvisedInterceptor.advisors:  

ArrayList holds all AOP notification method (Advisor) information related to the current proxy Bean.class. Custom AOP method is encapsulated by Spring as InstantiationModelAwarePointcutAdvisor type object. The default order=int.max. The order of the open transaction notification method is 2147483647 (int. max).

aopProxy.dynamicAdvisedInterceptor.advisors[2]:

Custom AOP notification methods are encapsulated in Spring as InstantiationModelAwarePointcutAdvisor type objects. The following figure shows the properties of the custom notification method.

advisors[2].pointcut: Cut-point information for custom AOP notification methods

shadowMatchCache: Map holds the matching results between the current notification method configuration tangent and each method in the proxy Bean.class. Matching results are the basis for creating AOP notification chains. Each method object in its key=Bean.class

 

Call the core process

When calling a method through an AOP-wrapped SpringBean object, the interception method of its proxy object's dynamic notification interceptor is executed first.

CglibAopProxy.DynamicAdvisedInterceptor#intercept

1. Obtaining AOP Notification Method Interceptor Chain

//Obtain the notification method interceptor chain of the current proxy method tagetMethod through DynamicAdvisedInterceptor.advised
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
      //Matching tagetMethod Interceptor Chain in Cache
      ->List<Object> cached = this.methodCache.get(cacheKey);
      //No hit cache
      ->if (cached == null)
          //Generating interceptor chain cached 
          ->cached =this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
					this, method, targetClass);
                  //Traversing class-related notification method information stored in proxy objects
                  ->for (advisor:advisors)  
                          //Does the notification method tangent expression match the target method?
                          -> if (advisor.pointcut.shadowMatchCache.get(tagetMethod).match==YES ) 
                                 ->cached.add(advisor)

          //Interceptor Chain Storage Cache
          ->this.methodCache.put(cacheKey, cached);
          ->return cached;

2. If the interceptor chain is empty, direct method/methodProxy.invoke reflects the target method return.

3. Interceptor chain is not empty, instantiate a MethodInvocation mi (new instantiation MI for each call) and recurse its proceed(). Mi contains an index (execution tag), execution chain...... And so on.

chain:ArrayList save order: Expose interceptor (0) - > transaction interceptor (1) - > after interceptor (2) - > around interceptor (3) - > before interceptor (4), recursive call mi.proceed().

Array + index + recursive implementation of chain call

(2)after interceptor invoke: first proceed to mi. proceed () - > chain [++ index]. invoke (), finally wait to be executed when returning to the stack.

(3)around interceptor invoke: reflection executes the @Around tangent method, calls joinPoint.proceed() in the tangent method, and continues to recurse mi. proceed - > chain [++ index]. invoke ()

(4) beforeinterceptor invoke: from (3) to mi.proceed(), if there is an interceptor in the chain, perform beforeface method - > recursive mi.proceed() - > chain [++ index]. invoke ().

(5) Finally, mi.proceed() executes to the end of the chain, index==chain.size, starts executing the target method, and return s the method out of the stack.

 

So the execution order of Spring AOP is: before around - > before - > target method - > after around - > after after.

//Each call instantiates a method caller, MethodInvocation, and recursively calls proceed
new CglibMethodInvocation(....).proceed();

//ReflectiveMethodInvocation#proceed
public Object proceed() throws Throwable {
		//This. current Interceptor Index = current index initial = - 1
	        //This. interceptors AndDynamicMethod Matchers = the chain of interceptors generated above

                 //Determine whether the interceptor chain has been invoked
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
                        //Execute target method, terminate recursion, method out of stack
			return invokeJoinpoint();
		}

                //Remove the current index+1 interceptor
		Object interceptorOrInterceptionAdvice =
		this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

                //Interceptor type detection for dynamic matching
		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			// Evaluate dynamic method matcher here: static part will already have
			// been evaluated and found to match.
			InterceptorAndDynamicMethodMatcher dm =
					(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
			Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());

			if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
				return dm.interceptor.invoke(this);
			}
			else {
				//Matching failed, skipping the current interceptor, next in the recursive interceptor chain
				return proceed();
			}
		}
		else {
                        //Interceptor type detection for static matching
			//Execute the interceptor, pass this in, and recurse the current method this.proceed() in invoke.
                        //This invoke executes differently depending on the Method Interceptor type
                        //Expose, @Around, @Before, @After... see invoke()
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
}


//ExposeInvocationInterceptor#invoke
//Expose type interceptor
 @Override
public Object invoke(MethodInvocation mi) throws Throwable {
                //The parameter mi is the above one.
		MethodInvocation oldInvocation = invocation.get();
                //ThreadLocal<MethodInvocation> invocation
                //Thread temporary mi
		invocation.set(mi);
		try {
                        //Recursive upper proceed method to the next interceptor chain
			return mi.proceed();
		}
		finally {
                        //Reset invocation
			invocation.set(oldInvocation);
		}
}

//AspectJAfterAdvice#invoke
//@ After interceptor
public Object invoke(MethodInvocation mi) throws Throwable {
		try {
                         //Recursive Next Interceptor
			return mi.proceed();
		}
		finally {
                         //proceed() terminates the recursion, exits the stack to execute finally at this time
                         //Because it is final, whether there is an exception or not, @After must be executed.
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
}

//AspectJAroundAdvice#invoke
//@ Around interceptor + execution target method + termination recursion + stack exit
public Object invoke(MethodInvocation mi) throws Throwable {
		if (!(mi instanceof ProxyMethodInvocation)) {
			throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
		}

                //Convert mi to ProxyMethod Invocation
		ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
                //Get JoinPoint
		ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
                //Get the matcher
		JoinPointMatch jpm = getJoinPointMatch(pmi);
                //Execution - > invokeAdvice Method With Given Args
		return invokeAdviceMethod(pjp, jpm, null, null);
}

//AbstractAspectJAdvice#invokeAdviceMethodWithGivenArgs
//@ The invokeAdviceMethod on the Around interceptor eventually executes to this method
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
		Object[] actualArgs = args;
                
		if (this.aspectJAdviceMethod.getParameterCount() == 0) {
			actualArgs = null;
		}
		try {
			ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
                        // Method annotated with @Around for aspectJAdviceMethod
                        // Method Reflection Executes @Around Section Method
                        // Call joinPoint.proceed() in the method in the tangent
                        // Continue to recursively proceed to execute before method + target method
			return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
                        //So far @Around tangent method + before method + target method have been executed, return out of the stack
		}
		catch (IllegalArgumentException ex) {
			throw new AopInvocationException("Mismatch on arguments to advice method [" +
					this.aspectJAdviceMethod + "]; pointcut expression [" +
					this.pointcut.getPointcutExpression() + "]", ex);
		}
		catch (InvocationTargetException ex) {
			throw ex.getTargetException();
		}
}



 

 

 

 

Posted by boinnk on Sat, 07 Sep 2019 00:42:08 -0700