1, Basic source code analysis
1. Find the entrance
Spring's AOP is started by accessing the BeanPostProcessor postprocessor
2.BeanPostProcessor
BeanPostProcessor is embodied in the doCreateBean of IOC source code analysis, the latter sentence of populateBean
Object exposedObject = bean; try { populateBean(beanName, mbd, instanceWrapper); exposedObject = initializeBean(beanName, exposedObject, mbd); }
In initializeBean, BeanPostProcessor is called before and after the invokeInitMethods initialization method is called.
Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { //... } if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); }
In fact, you call BeanPostProcessor's before and after methods before and after your init method.
In Spring, there are many implementation subclasses of BeanPostProcessor, which perform different operations respectively, such as AOP face-to-face programming registration notification adapter, Bean object data verification, Bean inheritance properties, method merging, etc.
Analyze the BeanPostProcessor subclass AbstractAutoProxyCreator (the classic implementation class AnnotationAwareAspectJAutoProxyCreator) that creates the AOP proxy object.
3.AbstractAutoProxyCreator
postProcessAfterInitialization of AbstractAutoProxyCreator, i.e. after method
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (!this.earlyProxyReferences.contains(cacheKey)) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }
The core logic is in wrapIfNecessary. The main steps are as follows
1. Judge whether the wrap wrapper (AOP agent) is cached or skipped by the basic Bean (Advice/PointCut/Advisor)
2. Get the advice of the Bean
3. Process advice to createProxy to create proxy object and cache
The core, of course, is createProxy, which is ultimately handed over to the factory proxyFactory.getProxy(), and finally to createAopProxy() method of DefaultAopProxyFactory
4.DefaultAopProxyFactory#createAopProxy()
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { //... } if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } }
There are two ways to generate proxy: JDKProxy and CGLib
Let's analyze how the JDK dynamic proxy works in spring. It's woven into the section, which corresponds to the JdkDynamicAopProxy
5.JdkDynamicAopProxy
Invocationhandler is the core of JDK dynamic proxy, and the method calls of generated proxy objects will be delegated to InvocationHandler.invoke() method. The source code of JdkDynamicAopProxy shows that this class also implements invocationhandler,
5.1 invoke() method:
After avoiding some special cases that are not aop, first obtain the Interceptor Chain applied to this method. If there is a notification, the notification is applied and JoinPoint is executed; if there is no notification, JoinPoint is executed directly by reflection.
5.2 access to notice chain
getInterceptorsAndDynamicInterceptionAdvice method:
1. Get the list of advisor s from the configuration instance config provided,
If it is an introduction Advisor, then judge whether the Advisor can be applied to the target class targetClass
3. If it is PointcutAdvisor, judge whether the Advisor can be applied to the target Method
4. Convert the qualified Advisor to the Interceptor list through the Advisor adapter
After this method is executed, the configuration in Advised can be applied to JoinPoint or Target Object
All the Advisor of has been converted into MethodInterceptor
5.3 execution
After getting the notification chain, it is executed:
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); if (chain.isEmpty()) { Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else { invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); retVal = invocation.proceed(); }
The core is retval= invocation.proceed (); open the processed source code of ReflectiveMethodInvocation:
public Object proceed() throws Throwable { //1. If the Interceptor is finished, execute joinPoint if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } Object interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); //2. If you want to dynamically match joinPoint InterceptorAndDynamicMethodMatcher dm =(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; //3. Dynamic matching: whether the parameters meet the matching conditions at runtime if (dm.MethodMatcher.matches(this.Method, this.targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else { //When dynamic matching fails, skip the current Interceptor and call the next Interceptor return proceed(); } } else { //4. Execute the current intercetor return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }
1. Take the Interceptor from the execution chain (sorted as before, after, return, after throwing)
2. In two cases, whether the Interceptor is dynamic matching
2.1 dynamic matching type, to execute dynamic matching code, and to match, execute
2.2 for general type else, directly execute Interceptor logic (in this logic, if the code is arranged, continue recursion or execute yourself first, and before execute yourself first) as follows:
invoke of beofore interceptor
public Object invoke(MethodInvocation mi) throws Throwable { this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis()); return mi.proceed(); }
After interceptor's invoke (continue recursion before executing yourself)
public Object invoke(MethodInvocation mi) throws Throwable { try { return mi.proceed(); } finally { invokeAdviceMethod(getJoinPointMatch(), null, null); } }