AOP execution process
When I talked about IOC, I talked about its startup process. Similarly, AOP also has a specified execution process, but it needs IOC as the basis.
- The IOC container is started to store objects
- Instantiate and initialize objects, and store the generated completed objects in the container (some objects in the container, such as beanfactoryprocessor, methodinterceptor, and many other objects)
- Get the required object from the created container
- Call the specific method to start the call
With so much theoretical knowledge, if you want to know the specific execution process, it's still the same. debug step by step and enter the source code viewing process
First, you need to prepare and configure a section
@Aspect @Component public class LogUtil { @Pointcut("execution(public * com.ao.bing.demo.spring.aop..*.*(..))") public void pctMethod() { } @Around(value = "pctMethod()") public Object around(ProceedingJoinPoint pjp) throws Throwable { Object ret = pjp.proceed(); System.out.println("Around advice"); return ret; } @Before("pctMethod()") public void before() { System.out.println("Before advice"); } @After(value = "pctMethod()") public void after() { System.out.println("After advice"); } @AfterReturning(value = "pctMethod()") public void afterReturning() { System.out.println("AfterReturning advice"); } @AfterThrowing(value = "pctMethod()") public void afterThrowing() { System.out.println("AfterThrowing advice"); } // main method test demo public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); AopTestDemo aopTestDemo = applicationContext.getBean(AopTestDemo.class); aopTestDemo.method("test AOP"); } }
Here, a profile demo of LogUtil is configured. All five notifications are written, and there is also a main method test. When the preparatory work is finished, the debug code will be officially started

First, we set a breakpoint in aopTestDemo. At this time, our past bean object aopTestDemo is already an object generated through dynamic proxy, in which there are many CALLBACK method attributes.
What are the properties of these methods?
In fact, this is related to the interceptor of Spring. In fact, it is a design pattern. The observer pattern is to monitor the behavior of objects. The notification function is realized through the callback mechanism.
Since it is a callback method, it should be advanced into the dynamicadiscedeinterceptor method
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable { private final AdvisedSupport advised; public DynamicAdvisedInterceptor(AdvisedSupport advised) { this.advised = advised; } @Nullable public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; Object target = null; TargetSource targetSource = this.advised.getTargetSource(); Object var16; try { if (this.advised.exposeProxy) { oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } target = targetSource.getTarget(); Class<?> targetClass = target != null ? target.getClass() : null; // Get the notification method of configured AOP from advised - key points List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); Object retVal; // If the notification method is not configured, the calling method of the target object is called directly if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = methodProxy.invoke(target, argsToUse); } else { // Start advice notification through CglibMethodInvocation - key retVal = (new CglibAopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed(); } retVal = CglibAopProxy.processReturnType(proxy, target, method, retVal); var16 = retVal; } finally { if (target != null && !targetSource.isStatic()) { targetSource.releaseTarget(target); } if (setProxyContext) { AopContext.setCurrentProxy(oldProxy); } } return var16; }
There is a list < Object > chain in the dynamic advised interceptor, where we can get the notification method we configured

As can be seen from the screenshot above, Spring first obtains all notifications and puts them in a list collection object. Because the list is not empty at this time, it will go to the process of starting advice notification through CglibMethodInvocation
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable { protected final Object proxy; @Nullable protected final Object target; protected final Method method; protected Object[] arguments = new Object[0]; @Nullable private final Class<?> targetClass; /** * Lazily initialized map of user-specific attributes for this invocation. */ @Nullable private Map<String, Object> userAttributes; /** * List of MethodInterceptor and InterceptorAndDynamicMethodMatcher * that need dynamic checks. */ protected final List<?> interceptorsAndDynamicMethodMatchers; /** * Index from 0 of the current interceptor we're invoking. * -1 until we invoke: then the current interceptor. */ private int currentInterceptorIndex = -1; // Omit other methods @Override @Nullable public Object proceed() throws Throwable { // We start with an index of -1 and increment early. // From the index -1 interceptor, it is called and incremented in sequence. If the call is completed in the entire List chain, the function of target will be called. // The specific implementation is in aoputils In the invokejoinpointusingreflection method, it is the method of realizing the target through reflection if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } // Get the next interceptor to be executed and process along the chain of defined interceptor or interception advice Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { // Evaluate dynamic method matcher here: static part will already have // been evaluated and found to match. // Dynamically match the interceptor. If it matches the defined pointcut, the current advice will be executed 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 { // Dynamic matching failed. // Skip this interceptor and invoke the next in the chain. return proceed(); } } else { // It's an interceptor, so we just invoke it: The pointcut will have // been evaluated statically before this object was constructed. // The common interceptor calls the interceptor directly, and uses the current this (CglibMethodInvocation) as a parameter to ensure the execution of the calling chain in the current instance. return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } } // Omit other methods }
One thing to note here is that from the above source code, the default value of currentInterceptorIndex is defined as - 1, which is equivalent to judging whether the execution of the current notification chain is completed. After the execution is completed, that is, call the target method directly through reflection, or execute downward.
((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this)
Interceptor orinterceptionadvice is the key point, that is, call the interceptor to execute the specific method
public final class ExposeInvocationInterceptor implements MethodInterceptor, PriorityOrdered, Serializable { @Override public Object invoke(MethodInvocation mi) throws Throwable { MethodInvocation oldInvocation = invocation.get(); invocation.set(mi); try { // Specific implementation return mi.proceed(); } finally { invocation.set(oldInvocation); } } }
I don't know if you have found the problem. In the screenshot above, there are 6 notification methods in the list < Object > chain, while only 5 methods are configured in the configured util,
First, this is the ExposeInvocationInterceptor method. What exactly is this?
In fact, this is another design pattern responsibility chain design pattern introduced by Spring. The reason for introducing this design pattern is that there are so many configured notification methods. How does spring know to execute that advice? Therefore, the ExposeInvocationInterceptor (the interceptor that exposes the caller) is used as the first notification method to ensure that all notification methods are executed in this connected manner.
At this point, the notification concatenation structure call process of spring AOP begins, and the circular call is repeated. Until the whole chain of List chain is executed
At present, there are some other logics that need to be explained in detail
For example, is there a sequential execution for the whole chain? Or is it executed according to the order in which the code is written?
org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator#sortAdvisors
After obtaining the whole responsibility chain, it will be sorted and executed once. By default, the topological sorting method is used. You can take a specific look at sortAdvisors
Then, when each notification method is executed, there will be a corresponding aspect notification method
org.springframework.aop.aspectj.AspectJAfterAdvice org.springframework.aop.aspectj.AspectJAfterReturningAdvice org.springframework.aop.aspectj.AspectJAfterThrowingAdvice org.springframework.aop.aspectj.AspectJAroundAdvice org.springframework.aop.aspectj.AspectJMethodBeforeAdvice The five notifications we configured correspond to the above five processing logic
Therefore, for the entire responsibility chain, the notification call link can be understood as a diagram structure:

The above is the whole execution process of Spring notification,
To sum up
There are five kinds of notifications in Spring. First, specific notifications are obtained through the startup process with Spring container, When calling an object, all the advice to be executed are first placed in a collection of chain objects through the dynamic proxy ASM technology, In order to ensure that the whole chain is called, the ExposeInvocationInterceptor will be called first by default to trigger the whole chain execution, After each advice is executed, it will return to the super processed method again to execute the next advice, When the failed advice is executed, there is a corresponding aspect notification method. When all the advice are executed, the target method is called through reflection In the whole process, you can try dubug by yourself. It's not a special trouble!!!
AOP transaction function
AOP handles common configuration aspects, logs and other services, and transactions are also familiar to us.
In fact, AOP transactions are also executed through configured advice

Notify the disassembly of advice to realize the function of transaction.
In Spring, you can realize the transaction function through @ Transactional annotation. Students who have seen the source code must have seen the TransactionAspectSupport class
public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean { // Omit other code.... @Nullable protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, final InvocationCallback invocation) throws Throwable { // If the transaction attribute is null, the method is non-transactional. TransactionAttributeSource tas = getTransactionAttributeSource(); final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null); final PlatformTransactionManager tm = determineTransactionManager(txAttr); final String joinpointIdentification = methodIdentification(method, targetClass, txAttr); if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) { // Standard transaction demarcation with getTransaction and commit/rollback calls. TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); Object retVal = null; try { // This is an around advice: Invoke the next interceptor in the chain. // This will normally result in a target object being invoked. retVal = invocation.proceedWithInvocation(); } catch (Throwable ex) { // target invocation exception // Exception rollback focus completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { cleanupTransactionInfo(txInfo); } // Submit key points after success commitTransactionAfterReturning(txInfo); return retVal; } // Omit other code.... }
Therefore, the declared transaction of spring AOP is also implemented through advice.
The transaction of AOP is relatively simple on the whole. To put it bluntly, it is to complete the transaction function through the new combination of advice. Of course, it is also the strength of Spring, and the scalability is really high.
summary
In order to enhance understanding, there are still two common interview questions
Notice execution process of advice?
If I still don't understand the whole process, I think I can debug it myself to deepen my understanding. I also make a summary in the article. But you should really understand it so that you won't be asked by the interviewer
How are Transactional transactions implemented in AOP?
If you understand the calling process of advice, you can easily answer this question.