Spring AOP implements source code analysis (3)


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

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326404038&siteId=291194637