Spring注解事务不支持 protect private 方法的原因

博客详细分析了Spring注解事务不支持保护私有方法的原因,从Bean的初始化过程到AOP代理的创建,深入探讨了事务管理的内部机制。重点在于事务属性源的计算过程中,对于非公共方法的忽略,导致私有方法无法被事务管理。此外,还介绍了Spring AOP如何根据切点匹配和通知方法来决定是否创建代理类。
摘要由CSDN通过智能技术生成

Spring注解事务不支持 protect private 方法的原因

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@Builder
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    @Tolerate
    public User() {
    }

    @TableId(value = "id", type = IdType.ID_WORKER)
    private Long id;

    private String name;

    private String password;

    private Integer age;
}
@Service
public class UserServiceImpl2 {

    @Resource
    private UserMapper userMapper;

    @Transactional
    void saveUser(User user) {
        userMapper.insert(user);
        // 测试事务回滚
        if (!StringUtils.hasText(user.getName())) {
            throw new RuntimeException("username不能为空");
        }
    }
}
@SpringBootApplication
@MapperScan("com.example.mapper")
public class ThreadApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(ThreadApplication.class, args);
        UserServiceImpl2 userService = context.getBean(UserServiceImpl2.class);
        User user = User.builder().age(20).build();
        userService.saveUser(user);
    }
}

现在 userService.saveUser(user);这里打个断点,debug方式启动,可以看到取出来的userService不是代理类,所以事务肯定不会生效。

image-20220309170926286

进入生成代理类的applyBeanPostProcessorsAfterInitialization方法,

@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
      throws BeansException {

   Object result = existingBean;
   for (BeanPostProcessor processor : getBeanPostProcessors()) {
      // postProcessAfterInitialization会判断bean是否需要生成代理类
      Object current = processor.postProcessAfterInitialization(result, beanName);
      if (current == null) {
         return result;
      }
      result = current;
   }
   return result;
}

AbstractAutoProxyCreator类重写了postProcessAfterInitialization方法

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
   if (bean != null) {
      Object cacheKey = getCacheKey(bean.getClass(), beanName);
      if (this.earlyProxyReferences.remove(cacheKey) != bean) {
         return wrapIfNecessary(bean, beanName, cacheKey);
      }
   }
   return bean;
}

为什么是AbstractAutoProxyCreator?看下@EnableAspectJAutoProxy注解,通@Import导入AspectJAutoProxyRegistrar往IOC容器中注入了一个类型为AnnotationAwareAspectJAutoProxyCreator的bean。AnnotationAwareAspectJAutoProxyCreator的继承结构如图所示,它的父类为AbstractAutoProxyCreator并且重写了postProcessAfterInitialization方法

image-20220309172650478

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
   boolean proxyTargetClass() default false;
   boolean exposeProxy() default false;
}
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
   @Override
   public void registerBeanDefinitions(
         AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

      // 重点是这里
      AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
      ......
   }
}
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
   return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
      BeanDefinitionRegistry registry, @Nullable Object source) {

   return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(
      Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

   Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

   //判断容器中是否有该类型的Bean
   if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
      BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
      if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
         int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
         int requiredPriority = findPriorityForClass(cls);
         if (currentPriority < requiredPriority) {
            apcDefinition.setBeanClassName(cls.getName());
         }
      }
      return null;
   }

   // 在引入spring aop starter,aop自动装配时容器中并不存在这个类型的Bean
   // 所以通过 RootBeanDefinition注册一个
   RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
   beanDefinition.setSource(source);
   beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
   beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
   registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
   return beanDefinition;
}

回到wrapIfNecessary方法

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
   ......
   // Create proxy if we have advice.
   // 获取该Bean对应的通知方法集合
   Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
   // 该Bean对应的通知方法集合为空,创建Bean的代理类
   if (specificInterceptors != DO_NOT_PROXY) {
      this.advisedBeans.put(cacheKey, Boolean.TRUE);
      // 创建Bean的代理类
      Object proxy = createProxy(
            bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
      this.proxyTypes.put(cacheKey, proxy.getClass());
      return proxy;
   }
   // 该Bean对应的通知方法集合为空,Bean不需要代理
   this.advisedBeans.put(cacheKey, Boolean.FALSE);
   return bean;
}

所以重点在getAdvicesAndAdvisorsForBean方法返回了空数组,getAdvicesAndAdvisorsForBean方法内部主要包含以下这些逻辑:

  • 获取所有的通知方法(切面里定义的各个方法);
  • 通过切点表达式判断这些通知方法是否可为当前Bean所用;
  • 如果有符合的通知方法,则对它们进行排序。

进入AbstractAdvisorAutoProxyCreator类的getAdvicesAndAdvisorsForBean方法。下面中间一大段都只是进入哪些方法看,不想看的直接看AbstractFallbackTransactionAttributeSource类的computeTransactionAttribute方法就好了

@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
      Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {

   // 进入这个方法
   List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
   if (advisors.isEmpty()) {
      return DO_NOT_PROXY;
   }
   return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
   List<Advisor> candidateAdvisors = findCandidateAdvisors();
   // 进入这个方法
   List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
   extendAdvisors(eligibleAdvisors);
   if (!eligibleAdvisors.isEmpty()) {
      eligibleAdvisors = sortAdvisors(eligibleAdvisors);
   }
   return eligibleAdvisors;
}
protected List<Advisor> findAdvisorsThatCanApply(
      List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {

   ProxyCreationContext.setCurrentProxiedBeanName(beanName);
   try {
      // 进入这个方法
      return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
   }
   finally {
      ProxyCreationContext.setCurrentProxiedBeanName(null);
   }
}
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);
      }
   }
   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;
}
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
   if (advisor instanceof IntroductionAdvisor) {
      return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
   }
   else if (advisor instanceof PointcutAdvisor) {
      PointcutAdvisor pca = (PointcutAdvisor) advisor;
      // 进入这个方法;
      return canApply(pca.getPointcut(), targetClass, hasIntroductions);
   }
   else {
      // It doesn't have a pointcut so we assume it applies.
      return true;
   }
}
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
   .......
   for (Class<?> clazz : classes) {
      Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
      for (Method method : methods) {
         if (introductionAwareMethodMatcher != null ?
               introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
               methodMatcher.matches(method, targetClass)) {
            // 进入methodMatcher.matches(method, targetClass),当方法修饰符不为public时,这里会返回false
            return true;
         }
      }
   }
   return false;
}

进入TransactionAttributeSourcePointcut类的matches方法

@Override
public boolean matches(Method method, Class<?> targetClass) {
   TransactionAttributeSource tas = getTransactionAttributeSource();
   // 进入getTransactionAttribute方法
   return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}

进入AbstractFallbackTransactionAttributeSource类的getTransactionAttribute方法

@Override
@Nullable
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);
      }
      ........
      return txAttr;
   }
}
@Nullable
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
   // Don't allow non-public methods, as configured.
   // 如果方法修饰符不是public 返回null,好了到了这里就结束了
   if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
      return null;
   }
   .....
   return null;
}

`

@Nullable
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
   // Don't allow non-public methods, as configured.
   // 如果方法修饰符不是public 返回null,好了到了这里就结束了
   if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
      return null;
   }
   .....
   return null;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值