Spring AOP知识学习

艺帆风顺 发布于 2025-04-03 22 次阅读


1. Spring AOP 代理核心类

Spring AOP 借助 AnnotationAwareAspectJAutoProxyCreator.class 类对其他 Bean 进行代理。该类的父类 AbstractAutoProxyCreator 实现了 BeanPostProcessor 接口,在 Bean 实例化时会调用 postProcessAfterInitialization 方法,此方法又会调用 wrapIfNecessary 方法:

  1. protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
  2.     // ...忽略部分代码
  3.     // Create proxy if we have advice.
  4.     Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
  5.     if (specificInterceptors != DO_NOT_PROXY) {
  6.         this.advisedBeans.put(cacheKey, Boolean.TRUE);
  7.         Object proxy = createProxy(
  8.                 bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
  9.         this.proxyTypes.put(cacheKey, proxy.getClass());
  10.         return proxy;
  11.     }
  12. }

上述方法会获取合法的 Advice 及 Advisor,进而创建代理。

2. 寻找合法的 Advisor

getAdvicesAndAdvisorsForBean 方法会调用 findEligibleAdvisors 方法:

  1. protected ListAdvisor> findEligibleAdvisors(Class> beanClass, String beanName) {
  2.     ListAdvisor> candidateAdvisors = findCandidateAdvisors(); // 获取所有Advisor
  3.     ListAdvisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); // 寻找合法的Advisor
  4.     extendAdvisors(eligibleAdvisors);
  5.     if (!eligibleAdvisors.isEmpty()) {
  6.         eligibleAdvisors = sortAdvisors(eligibleAdvisors);
  7.     }
  8.     return eligibleAdvisors;
  9. }

进一步查看 findAdvisorsThatCanApply 方法中的 canApply 方法:

  1. public static boolean canApply(Advisor advisor, Class> targetClass, boolean hasIntroductions) {
  2.     if (advisor instanceof IntroductionAdvisor) {
  3.         return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
  4.     }
  5.     else if (advisor instanceof PointcutAdvisor) {
  6.         PointcutAdvisor pca = (PointcutAdvisor) advisor;
  7.         return canApply(pca.getPointcut(), targetClass, hasIntroductions);
  8.     }
  9.     else {
  10.         // It doesn't have a pointcut so we assume it applies.
  11.         return true;
  12.     }
  13. }

若 Advisor 是 PointcutAdvisor 的子类,则会调用 canApply(pca.getPointcut(), targetClass, hasIntroductions) 方法:

  1. public static boolean canApply(Pointcut pc, Class> targetClass, boolean hasIntroductions) {
  2.     if (!pc.getClassFilter().matches(targetClass)) {
  3.         return false;
  4.     }
  5.     MethodMatcher methodMatcher = pc.getMethodMatcher();
  6.     if (methodMatcher == MethodMatcher.TRUE) {
  7.         // No need to iterate the methods if we're matching any method anyway...
  8.         return true;
  9.     }
  10.     IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
  11.     if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
  12.         introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
  13.     }
  14.     SetClass>> classes = new LinkedHashSet();
  15.     if (!Proxy.isProxyClass(targetClass)) {
  16.         classes.add(ClassUtils.getUserClass(targetClass));
  17.     }
  18.     classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
  19.     for (Class> clazz : classes) {
  20.         Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
  21.         for (Method method : methods) {
  22.             if (introductionAwareMethodMatcher != null ?
  23.                     introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
  24.                     methodMatcher.matches(method, targetClass)) {
  25.                 return true;
  26.             }
  27.         }
  28.     }
  29.     return false;
  30. }

上述代码先判断 Pointcut 的 classFilter 是否能匹配目标 Bean,接着获取 MethodMatcher,调用其 matches 方法匹配目标 Bean 所有接口中的方法。

3. Spring tx 模块判断 Bean 事务开启步骤

3.1 解析 annotation - driven 标签

查看 Spring 解析 annotation - driven 标签的解析器 AnnotationDrivenBeanDefinitionParser 类,其 parse 方法注册了三个类:

  • BeanFactoryTransactionAttributeSourceAdvisor.class:实现了 PointcutAdvisor 接口。
  • AnnotationTransactionAttributeSource.class
  • TransactionInterceptor.class

AnnotationTransactionAttributeSource 和 TransactionInterceptor 是 BeanFactoryTransactionAttributeSourceAdvisor 的属性。BeanFactoryTransactionAttributeSourceAdvisor 的属性 pointcut 代码如下:

  1. private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
  2.     @Override
  3.     @Nullable
  4.     protected TransactionAttributeSource getTransactionAttributeSource() {
  5.         return transactionAttributeSource;
  6.     }
  7. };

3.2 TransactionAttributeSourcePointcut 类的 classFilter 设置

TransactionAttributeSourcePointcut 类的构造方法设置了 classFilter

  1. protected TransactionAttributeSourcePointcut() {
  2.     setClassFilter(new TransactionAttributeSourceClassFilter());
  3. }

3.3 判断目标类是否可代理

回顾前面分析的 canApply 方法,第一步是获取 pointcut 的 classfilter,调用其 matches 方法判断目标类是否能进行代理。Spring tx 获取到的 classfilter 为 TransactionAttributeSourceClassFilter,其 matches 方法实现如下:

  1. private class TransactionAttributeSourceClassFilter implements ClassFilter {
  2.     @Override
  3.     public boolean matches(Class> clazz) {
  4.         if (TransactionalProxy.class.isAssignableFrom(clazz) ||
  5.                 PlatformTransactionManager.class.isAssignableFrom(clazz) ||
  6.                 PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) {
  7.             return false;
  8.         }
  9.         TransactionAttributeSource tas = getTransactionAttributeSource();
  10.         return (tas == null || tas.isCandidateClass(clazz));
  11.     }
  12. }

getTransactionAttributeSource() 方法会调用到 BeanFactoryTransactionAttributeSourceAdvisor 的 private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() 处,返回初始化类时设置的 AnnotationTransactionAttributeSource 类实例。

3.4 判断目标类是否为候选类

tas.isCandidateClass(clazz) 代码如下:

  1. public boolean isCandidateClass(Class> targetClass) {
  2.     for (TransactionAnnotationParser parser : this.annotationParsers) {
  3.         if (parser.isCandidateClass(targetClass)) {
  4.             return true;
  5.         }
  6.     }
  7.     return false;
  8. }

3.5 获取 MethodMatcher

TransactionAttributeSourcePointcut 的父类 StaticMethodMatcherPointcut 的 getMethodMatcher 方法实现为 return this,所以会调用 TransactionAttributeSourcePointcut 的 matches 方法:

  1. @Override
  2. public boolean matches(Method method, Class> targetClass) {
  3.     TransactionAttributeSource tas = getTransactionAttributeSource();
  4.     return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
  5. }

同样会调用 AnnotationTransactionAttributeSource 的 getTransactionAttribute 方法:

  1. public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class> targetClass) {
  2.     Object cacheKey = getCacheKey(method, targetClass);
  3.     TransactionAttribute cached = this.attributeCache.get(cacheKey);
  4.     if (cached != null) {
  5.         if (cached == NULL_TRANSACTION_ATTRIBUTE) {
  6.             return null;
  7.         }
  8.         else {
  9.             return cached;
  10.         }
  11.     }
  12.     else {
  13.         TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
  14.         if (txAttr == null) {
  15.             this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
  16.         }
  17.         else {
  18.             String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
  19.             if (txAttr instanceof DefaultTransactionAttribute) {
  20.                 ((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
  21.             }
  22.             this.attributeCache.put(cacheKey, txAttr);
  23.         }
  24.         return txAttr;
  25.     }
  26. }

3.6 计算事务属性

继续查看 computeTransactionAttribute 方法:

  1. protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class> targetClass) {
  2.     // Don't allow no - public methods as required.
  3.     if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
  4.         return null;
  5.     }
  6.     // The method may be on an interface, but we need attributes from the target class.
  7.     // If the target class is null, the method will be unchanged.
  8.     Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
  9.     // First try is the method in the target class.
  10.     TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
  11.     if (txAttr != null) {
  12.         return txAttr;
  13.     }
  14.     // Second try is the transaction attribute on the target class.
  15.     txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
  16.     if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
  17.         return txAttr;
  18.     }
  19.     if (specificMethod != method) {
  20.         // Fallback is to look at the original method.
  21.         txAttr = findTransactionAttribute(method);
  22.         if (txAttr != null) {
  23.             return txAttr;
  24.         }
  25.         // Last fallback is the class of the original method.
  26.         txAttr = findTransactionAttribute(method.getDeclaringClass());
  27.         if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
  28.             return txAttr;
  29.         }
  30.     }
  31.     return null;
  32. }

该方法第一行判断 Method 是否为 public,只有 public 方法才合法。

接下来调用 findTransactionAttribute(specificMethod) 方法寻找方法上的事务注解,如果找不到,则调用 findTransactionAttribute(specificMethod.getDeclaringClass()) 寻找类上的事务注解,如果找到事务配置,则说明该方法应该被代理。