关联博文:
SpringBoot中事务执行原理分析(一)
SpringBoot中事务执行原理分析(二)
SpringBoot中事务执行原理分析(三)
SpringBoot中事务执行原理分析(四)
SpringBoot中事务执行原理分析(五)
SpringBoot中事务执行原理分析(六)
SpringBoot中事务执行原理分析补充篇
你认真研究过Spring中的@EnableTransactionManagement注解吗?
本文是对SpringBoot中事务执行原理分析(一)的补充说明,我们详细分析一下如何判断Advisor与我们的service是否匹配。
【1】几个核心类
在前文中我们提到了BeanFactoryTransactionAttributeSourceAdvisor,其包含了Advice用于对我们的service进行增强实现事务效果。
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor { @Nullable private TransactionAttributeSource transactionAttributeSource; private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() { @Override @Nullable protected TransactionAttributeSource getTransactionAttributeSource() { return transactionAttributeSource; } }; //... } //ProxyTransactionManagementConfiguration中定义了advicetransactionInterceptor @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor( TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) { BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor(); advisor.setTransactionAttributeSource(transactionAttributeSource); advisor.setAdvice(transactionInterceptor); if (this.enableTx != null) { advisor.setOrder(this.enableTx.<Integer>getNumber("order")); } return advisor; }
TransactionAttributeSourcePointcut 就是我们AOP概念中的pointcut,用于判断类/方法是否匹配。如下所示其还设置了ClassFilter为TransactionAttributeSourceClassFilter用于类级别的判断。
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable { protected TransactionAttributeSourcePointcut() { setClassFilter(new TransactionAttributeSourceClassFilter()); } //... }
TransactionAttributeSource其是一个策略接口被TransactionInterceptor使用来检测元数据信息。在本文这里其实际是AnnotationTransactionAttributeSource,这个在ProxyTransactionManagementConfiguration这个配置类中有定义。
@Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public TransactionAttributeSource transactionAttributeSource() { //空参构造,publicMethodsOnly默认为true return new AnnotationTransactionAttributeSource(); }
这里要特别注意publicMethodsOnly 属性与annotationParsers 属性。前者标明是否只允许public方法,后者则是注解解析器。
public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) { // 默认为true,表示只允许public方法 this.publicMethodsOnly = publicMethodsOnly; if (jta12Present || ejb3Present) { this.annotationParsers = new LinkedHashSet<>(4); this.annotationParsers.add(new SpringTransactionAnnotationParser()); if (jta12Present) { this.annotationParsers.add(new JtaTransactionAnnotationParser()); } if (ejb3Present) { this.annotationParsers.add(new Ejb3TransactionAnnotationParser()); } } else { //指定注解解析器 this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser()); } }
SpringTransactionAnnotationParser主要作用就是用来解析事务注解信息(@Transactional)。
【2】Advisor是如何匹配我们的service呢?
在AopUtils的findAdvisorsThatCanApply会对找到的Advisor进行逐一判断,鉴定其是否适用于我们的service。
如下所示在AopUtils的canApply方法中首先使用ClassFilter进行判断,然后获取到MethodMatcher 对class和method进行遍历循环判断。
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) { Assert.notNull(pc, "Pointcut must not be null"); // 首先使用classFilter进行判断 if (!pc.getClassFilter().matches(targetClass)) { return false; } //获取到MethodMatcher 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; } //获取到目标类、超类 Set<Class<?>> classes = new LinkedHashSet<>(); if (!Proxy.isProxyClass(targetClass)) { classes.add(ClassUtils.getUserClass(targetClass)); } classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass)); //对目标类与超类的所有方法进行遍历、判断 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)) { return true; } } } return false; }
① 类级别的判断
也就是下面这句代码, 前面我们提到过TransactionAttributeSourcePointcut
中的classFilter是TransactionAttributeSourceClassFilter
。
pc.getClassFilter().matches(targetClass)
其是TransactionAttributeSourcePointcut的成员内部类(非静态内部类),我们看下其matches方法:
@Override public boolean matches(Class<?> clazz) { if (TransactionalProxy.class.isAssignableFrom(clazz) || PlatformTransactionManager.class.isAssignableFrom(clazz) || PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) { return false; } TransactionAttributeSource tas = getTransactionAttributeSource(); return (tas == null || tas.isCandidateClass(clazz)); }
也就是说如果是TransactionalProxy、PlatformTransactionManager或者PersistenceExceptionTranslator,直接返回false。否则判断TransactionAttributeSource 是否为null或者TransactionAttributeSource的isCandidateClass方法是否为true。
如下所示,其将会遍历持有的TransactionAnnotationParser ,触发其isCandidateClass方法。
//AnnotationTransactionAttributeSource#isCandidateClass @Override public boolean isCandidateClass(Class<?> targetClass) { for (TransactionAnnotationParser parser : this.annotationParsers) { if (parser.isCandidateClass(targetClass)) { return true; } } return false; }
本文我们只有一个SpringTransactionAnnotationParser,我们继续看SpringTransactionAnnotationParser解析器的isCandidateClass方法。
@Override public boolean isCandidateClass(Class<?> targetClass) { return AnnotationUtils.isCandidateClass(targetClass, Transactional.class); }
其只是触发了AnnotationUtils的isCandidateClass方法,如下所示可以说基本对我们的service来说都返回true。
public static boolean isCandidateClass(Class<?> clazz, String annotationName) { //如果注解名称以java.开头,直接返回true if (annotationName.startsWith("java.")) { return true; } //如果clazz.getName以java.开头或者是Ordered类型 if (AnnotationsScanner.hasPlainJavaAnnotationsOnly(clazz)) { return false; } //直接返回true return true; }
② 方法级别的判断
OK,我们往下再看方法级别如何判断。这里触发的是TransactionAttributeSourcePointcut的matches方法。其获取到TransactionAttributeSource ,如果tas为null或者使用tas获取到的事务属性信息不为null,则返回true。
@Override public boolean matches(Method method, Class<?> targetClass) { TransactionAttributeSource tas = getTransactionAttributeSource(); return (tas == null || tas.getTransactionAttribute(method, targetClass) != null); }
如下图所示,AbstractFallbackTransactionAttributeSource的computeTransactionAttribute
方法中首先会根据publicMethodsOnly属性和方法的修饰符进行判断,如果非public则直接返回null(默认情况下publicMethodsOnly=true)。
然后将会从当前类进行级联查找方法上的事务注解信息,也就是说你的service如果实现了接口,那么在接口的方法上添加@Transactional(rollbackFor = Exception.class)
也是OK的。
如何获取方法上的注解信息呢,这里就用到了SpringTransactionAnnotationParser,其将会级联检索方法上的事务注解。获取到的事务注解信息如下所示:
确定了Advisor与我们的service匹配后,就可以为我们的service创建代理进行实现事务增强了。