Introduction to the Advisor interface family of the springAop principle and how to associate the Advisor with the bean in the advisor analysis source code associated with the spring transaction annotation @Transactional

1. Interface overview

 Advisor: Contains the basic interface for AOP notifications (actions taken at the connection point) and a filter that determines the applicability of the recommendation (for example, an entry point). This interface is not for use by Spring users, but allows versatility in supporting different types of notifications. Spring AOP is based on the surrounding notification delivery through method interception, which complies with the AOP Alliance interception API. The Advisor interface supports different types of recommendations, such as before and after notifications, without the need to use interception implementations.

PointcutAdvisor: The super interface of all Advisors driven by pointcuts. This covers almost all Advisors except introduction advisors. PointcutAdvisor contains a Pointcut member variable, which is the point of cut. Adding the Advice in the Advisor interface, it forms a complete aspect.

StaticMethodMatcherPointcutAdvisor: The aspect defined by the static method matcher cutpoint, which matches all target classes by default. (Shiro permission design is achieved by inheriting this class).

InstantiationModelAwarePointcutAdvisor: This interface has the only implementation class InstantiationModelAwarePointcutAdvisorImpl. This class is the Advisor after the aspect that we usually implement through aspectj annotations in the project is packaged.

AspectJExpressionPointcutAdvisor: Used for AspectJ pointcut expression to define the aspect of the pointcut

AbstractPointcutAdvisor: An abstract base class implemented by PointcutAdvisor, which can be a subclass that returns a specific pointcut/notification or a freely configurable pointcut/notification

Second, how does spring determine whether a bean needs to be proxied?

After spring has created the bean, it needs to determine whether it needs to create a proxy object for the current bean. The doCreateBean method in the org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory class will then call the applyBeanPostProcessorsAfterInitialization method, which will call the postProcessAfterInitialization of all BeanPostProcessors. org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator is a BeanPostProcessor, the postProcessAfterInitialization of this class will call the wrapIfNecessary method, that is, whether the bean needs to be wrapped into a proxy object. The principle of whether a proxy is required is whether the bean has an Advisor related to it, and then proxy.

Third, how does spring find all Advisor source codes and how to determine which Advisor a bean is associated with?

Part of the source code of wrapIfNecessary

// Create proxy if we have advice.
//获取bean有关的Advisor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
   this.advisedBeans.put(cacheKey, Boolean.TRUE);
   Object proxy = createProxy(
         bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
   this.proxyTypes.put(cacheKey, proxy.getClass());
   return proxy;
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
  //查找所有的Advisor
   List<Advisor> candidateAdvisors = findCandidateAdvisors();
  //查找所有的Advisor中可应用的某个bean的Advisor
   List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
   extendAdvisors(eligibleAdvisors);
   if (!eligibleAdvisors.isEmpty()) {
      eligibleAdvisors = sortAdvisors(eligibleAdvisors);
   }
   return eligibleAdvisors;
}

The source code of findCandidateAdvisors() can be summarized simply as follows: Get all the classes that implement Advisor from the container, and add the Advisor created by aspectJ.

Write down and look at the source code of findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName)

protected List<Advisor> findAdvisorsThatCanApply(
      List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
   //在ThreadLocal中标记当前beanName
   ProxyCreationContext.setCurrentProxiedBeanName(beanName);
   try {
      return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
   }
   finally {
     //在ThreadLocal中移除当前beanName
      ProxyCreationContext.setCurrentProxiedBeanName(null);
   }
}

AopUtils findAdvisorsThatCanApply source code analysis

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
   if (candidateAdvisors.isEmpty()) {
      return candidateAdvisors;
   }
   List<Advisor> eligibleAdvisors = new ArrayList<>();
   for (Advisor candidate : candidateAdvisors) {
      //是否为引入切面并且是否能被应用到
      if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
         eligibleAdvisors.add(candidate);
      }
   }
   //目前用不到,所以值为false
   boolean hasIntroductions = !eligibleAdvisors.isEmpty();
   for (Advisor candidate : candidateAdvisors) {
      if (candidate instanceof IntroductionAdvisor) {
         // already processed
         continue;
      }
      if (canApply(candidate, clazz, hasIntroductions)) {
         eligibleAdvisors.add(candidate);
      }
   }
   return eligibleAdvisors;
}

Take BeanFactoryTransactionAttributeSourceAdvisor (Advisor associated with transaction annotation) as an example, analyze the following source code. The cut point of BeanFactoryTransactionAttributeSourceAdvisor is TransactionAttributeSourcePointcut, TransactionAttributeSourcePointcut inherits StaticMethodMatcherPointcut, and the ClassFilter corresponding to StaticMethodMatcherPointcut is TrueClassFilter, so any class will be matched in one place.

StaticMethodMatcherPointcut inherits StaticMethodMatcher, so the MethodMatcher of TransactionAttributeSourcePointcut is TransactionAttributeSourcePointcut itself. So what is executed in 2 is the matches(Method method, Class<?> targetClass) method of TransactionAttributeSourcePointcut

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
   Assert.notNull(pc, "Pointcut must not be null");  
   //1
  if (!pc.getClassFilter().matches(targetClass)) {
      return false;
   }

   MethodMatcher methodMatcher = pc.getMethodMatcher();
   if (methodMatcher == MethodMatcher.TRUE) {
      // No need to iterate the methods if we're matching any method anyway...
      return true;
   }

   IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
   if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
      introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
   }
  //Find all interfaces implemented by the current class and its ancestor classes 
   Set<Class<?>> classes = new LinkedHashSet<>(); 
   if (!Proxy.isProxyClass(targetClass)) { 
      classes.add(ClassUtils.getUserClass(targetClass) ); 
   } 
   classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass)); 

   for (Class<?> clazz: classes) { 
      //Get the method list including methods inherited from the parent class 
      Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz) ; 
      for (Method method: methods) { 
        //2 
         if (introductionAwareMethodMatcher != null? 
               introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions): 
               methodMatcher.matches(method, targetClass)) { 
            return true; 
         } 
      } 
   }

   return false;
}

TransactionAttributeSourcePointcut的matches(Method method, Class<?> targetClass)源码:

@Override
public boolean matches(Method method, Class<?> targetClass) {
   if (TransactionalProxy.class.isAssignableFrom(targetClass) ||
         PlatformTransactionManager.class.isAssignableFrom(targetClass) ||
         PersistenceExceptionTranslator.class.isAssignableFrom(targetClass)) {
      return false;
   }
   TransactionAttributeSource tas = getTransactionAttributeSource();
   return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}

First judge whether TransactionalProxy, PlatformTransactionManager, PersistenceExceptionTranslator are the parent classes of the current class, if yes, return false. We found that TransactionAttributeSourcePointcut is actually an abstract class, and getTransactionAttributeSource in TransactionAttributeSourcePointcut is also an abstract method. From the source code of BeanFactoryTransactionAttributeSourceAdvisor, we can see that this method has been overridden when BeanFactoryTransactionAttributeSourceAdvisor defines TransactionAttributeSourcePointcut

private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
   @Override
   @Nullable
   protected TransactionAttributeSource getTransactionAttributeSource() {
      return transactionAttributeSource;
   }
};

The returned TransactionAttributeSource is a member variable of BeanFactoryTransactionAttributeSourceAdvisor. The BeanFactoryTransactionAttributeSourceAdvisor is configured by spring through @bean (transactionAdvisor() method of ProxyTransactionManagementConfiguration)

@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
   BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
   advisor.setTransactionAttributeSource(transactionAttributeSource());
   advisor.setAdvice(transactionInterceptor());
   if (this.enableTx != null) {
      advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
   }
   return advisor;
}

@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
   return new AnnotationTransactionAttributeSource();
}

So the final TransactionAttributeSource is AnnotationTransactionAttributeSource. AnnotationTransactionAttributeSource calling getTransactionAttribute(method, targetClass) is actually calling the method in the parent class AbstractFallbackTransactionAttributeSource

public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
   if (method.getDeclaringClass() == Object.class) {
      return null;
   }

   // First, see if we have a cached value.
   Object cacheKey = getCacheKey(method, targetClass);
   TransactionAttribute cached = this.attributeCache.get(cacheKey);
   if (cached != null) {
      // Value will either be canonical value indicating there is no transaction attribute,
      // or an actual transaction attribute.
      if (cached == NULL_TRANSACTION_ATTRIBUTE) {
         return null;
      }
      else {
         return cached;
      }
   }
   else {
      // We need to work it out.
      TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
      // Put it in the cache.
      if (txAttr == null) {
         this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
      }
      else {
         String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
         if (txAttr instanceof DefaultTransactionAttribute) {
            ((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
         }
         if (logger.isTraceEnabled()) {
            logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
         }
         this.attributeCache.put(cacheKey, txAttr);
      }
      return txAttr;
   }
}

computeTransactionAttribute(method, targetClass) continues down to call findTransactionAttribute(Method method) and findTransactionAttribute(Class<?> clazz) in AnnotationTransactionAttributeSource to find whether there is Transactional annotation on the method or class.

 

 

Guess you like

Origin blog.csdn.net/sinat_33472737/article/details/105414097