2, End of spring AOP (in supplement...)

Posted by ghostrider1 on Sat, 13 Jun 2020 07:56:32 +0200

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);
   }
}

Topics: Spring JDK Programming