The implementation of Spring AOP can be divided into three parts:
1. Register the specific implementation class of the AOP function
2. AOP entry when instantiating ordinary beans
3. AOP cuts into the specific process
Let's analyze how aop cuts in during the execution of BeanPostProcessor. As mentioned in the previous section, the initialization of ordinary beans will call the following methods
// Call the real implementation method entry of AOP result = beanProcessor.postProcessAfterInitialization(result, beanName);aop This method is actually inherited from AbstractAutoProxyCreator, track the implementation of postProcessAfterInitialization
There are really only two steps to creating an agent
1. Get the enhancement method or enhancer
2. Proxy according to the obtained enhancer
// class @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (!this.earlyProxyReferences.contains(cacheKey)) { // do aop packaging return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; } protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { // 1. Get the enhancer, which will be split in detail below Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); // If the aop interceptor is obtained if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); // 2. Create the proxy Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); // Finally return the aop proxy class return proxy; }
First trace the logic of getting the booster
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) { // encapsulated in a function List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); if (advisors.isEmpty()) { return DO_NOT_PROXY; } return advisors.toArray(); } protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { // Get the enhancer, and its internal implementation is as follows: // 1. Get all beanNames of beanFactory // 2. Traverse all beanNames and find the class declared as AspectJ // 3. Extract the enhancer for the class in the second step // 4. Add the extraction result to the cache (to improve the efficiency of the next call, because each bean will go through this process) // The enhancer will actually initialize different classes according to the annotations on the method (Before, After...), such as the Before annotation corresponds to AspectJMethodBeforeAdvice List<Advisor> candidateAdvisors = findCandidateAdvisors(); // Determine the available enhancers for the current bean, because not all enhancers are applicable to the current bean List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply (candidateAdvisors, beanClass, beanName); extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; }Keep track of creating proxy implementations
protected Object createProxy( Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) { ...... // Unified processing to encapsulate all enhancers Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); ...... // Generate proxy and return, there are two ways to generate proxy // For classes that implement interfaces, jdk dynamic proxy is used by default; for classes that do not implement interfaces, only cglib can be used // For classes that implement the interface, you can force the use of cglib (by configuring proxy-target-class="true") return proxyFactory.getProxy(getProxyClassLoader()); }The actual implementation of the proxy (jdk dynamic proxy, or cglib) will not be repeated here. For example, dynamic proxy will eventually call invoke. Let’s take a look at the invoke implementation of JdkDynamicAopProxy. The enhancer call chain is saved internally through the chain, and the implementation process is similar to responsibilities. chain design pattern
// class JdkDynamicAopProxy public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { ...... // Get and encapsulate the call chain chain, which will actually convert the advisor, such as (@Before annotation) AspectJMethodBeforeAdvice Will be converted to MethodBeforeAdviceInterceptor List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); if (chain.isEmpty()) { Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else { // delegate method execution invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // The actual execution is more interesting, it will loop chain, but you need to look at the logic carefully to understand retVal = invocation.proceed(); } ...... } public Object proceed() throws Throwable { // interceptorsAndDynamicMethodMatchers is actually the above call chain chain, if it reaches the end of the queue, it will jump out if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } // Get the next interceptor Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); ...... // In this method, this is passed in, and the implementation in it can be seen that after executing the invoke method of the current interceptor, this.proceed is executed, that is, the current proceed method is called back to ensure that the loop chain is completed. return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this); } // Such as the implementation of MethodBeforeAdviceInterceptor @Override public Object invoke(MethodInvocation mi) throws Throwable { // advice wraps advisor this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() ); // mi is the this passed in by the above invoke method return mi.proceed(); }