前言
本篇博文定位为为事务相关的其余博文的工具博文,属于Spring事务相关的基础类的打点、扫盲篇。
因为Spring的事务属于它非常非常重要的一块,因此内部的一些核心类、核心API有必要做个系统的了解,才能更好的了解到其深意。
TransactionAttribute
这个接口是在TransactionDefinition的基础上的扩展
// 它继承自TransactionDefinition ,所有可以定义事务的基础属性 public interface TransactionAttribute extends TransactionDefinition { // 返回与此事务属性关联的限定符值 //@since 3.0 @Nullable String getQualifier(); // Should we roll back on the given exception? boolean rollbackOn(Throwable ex); }
它的主要实现类有:DefaultTransactionAttribute、RuleBasedTransactionAttribute、DelegatingTransactionAttribute
DefaultTransactionAttribute
默认的事务属性实现,也是最常用的一个实现。
// 它继承自DefaultTransactionDefinition public class DefaultTransactionAttribute extends DefaultTransactionDefinition implements TransactionAttribute { @Nullable private String qualifier; @Nullable private String descriptor; // 你自己也可以自定义一个TransactionAttribute other 来替换掉一些默认行为 public DefaultTransactionAttribute() { super(); } public DefaultTransactionAttribute(TransactionAttribute other) { super(other); } // @since 3.0 public void setQualifier(@Nullable String qualifier) { this.qualifier = qualifier; } @Override @Nullable public String getQualifier() { return this.qualifier; } ... // 可以清晰的看到:默认只回滚RuntimeException 或者 Error(比如OOM这种) @Override public boolean rollbackOn(Throwable ex) { return (ex instanceof RuntimeException || ex instanceof Error); } }
RuleBasedTransactionAttribute
这个在基础实现的基础上扩展了一下,扩展了一些规则。
public class RuleBasedTransactionAttribute extends DefaultTransactionAttribute implements Serializable { /** Prefix for rollback-on-exception rules in description strings. */ public static final String PREFIX_ROLLBACK_RULE = "-"; /** Prefix for commit-on-exception rules in description strings. */ public static final String PREFIX_COMMIT_RULE = "+"; // RollbackRuleAttribute:它是个实体类,确定给定异常是否应导致回滚的规则 // 相当于封装了这个规则的一个实体,内部封装一个异常 提供一个实例变量: 这个变量相当于回滚规则为只回滚RuntimeException // public static final RollbackRuleAttribute ROLLBACK_ON_RUNTIME_EXCEPTIONS = new RollbackRuleAttribute(RuntimeException.class); // 所以此类最重要的一个属性,就是这个,它能维护多种回滚的规则~~~~ @Nullable private List<RollbackRuleAttribute> rollbackRules; ... public List<RollbackRuleAttribute> getRollbackRules() { if (this.rollbackRules == null) { this.rollbackRules = new LinkedList<>(); } return this.rollbackRules; } // 核心逻辑输入,复写了父类的rollbackOn方法。也就是看看当前异常是否需要回滚呢??? @Override public boolean rollbackOn(Throwable ex) { RollbackRuleAttribute winner = null; int deepest = Integer.MAX_VALUE; // 这里getDepth()就是去看看异常栈里面 该类型的异常处于啥位置。 // 这里用了Integer的最大值,基本相当于不管异常有多深,遇上此异常都应该回滚喽,也就是找到这个winnner了~~~~~ if (this.rollbackRules != null) { for (RollbackRuleAttribute rule : this.rollbackRules) { int depth = rule.getDepth(ex); if (depth >= 0 && depth < deepest) { deepest = depth; winner = rule; } } } // User superclass behavior (rollback on unchecked) if no rule matches. // 这句相当于:如果你没有指定回滚规则,那就交给父类吧(只回滚RuntimeException和Error类型) if (winner == null) { return super.rollbackOn(ex); } // 最终只要找到了,但是不是NoRollbackRuleAttribute类型就成`~~~~ return !(winner instanceof NoRollbackRuleAttribute); } }
DelegatingTransactionAttribute
很显然,它就是一个简单的代理,内部持有一个TransactionAttribute的引用。自己也是个抽象类,没做啥事,此处略过。它也继承自:DelegatingTransactionDefinition
TransactionDefinition
事务的定义,上面已经介绍了一个重要分支:TransactionAttribute。接下来继续介绍另外一个分支:
DelegatingTransactionDefinition
一样的也就是个代理抽象类,啥都木有做。内部持有一个TransactionDefinition targetDefinition的引用而已,所有方法都是委托给targetDefinition去做的
ResourceTransactionDefinition
这个子接口非常的新,是Spring5.1才提供的
// @since 5.1 // 指示资源事务,尤其是事务性资源是否准备好进行本地优化 public interface ResourceTransactionDefinition extends TransactionDefinition { // 确定事务性资源是否准备好进行本地优化 // @see #isReadOnly() boolean isLocalResource(); }
它和ResourceTransactionManager的使用相关联。ResourceTransactionManager是PlatformTransactionManager的一个子接口。
我们最常用的事务管理器DataSourceTransactionManager也实现了这个接口~~~~
目前Spring还未提供任何ResourceTransactionDefinition它的具体实现~
TransactionAttributeSource:事务属性源
它位于包:org.springframework.transaction.interceptor
它有点类似于之前讲过的TargetSource
,它也是对TransactionAttribute
进行了一层包装~~
public interface TransactionAttributeSource { // 通过Method和目标类,拿到事务属性~~~ // 比如我们的@Transaction是标注在方法上的,可议自定义方法级别的事务属性,用它就特别的方便~ @Nullable TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass); }
这里有很多人不明白了,为何都给了Method,为啥还要传入Class呢?难道Method还不知道它所属的类???
这里做如下解释:
- method – 目前正在进行的方法调用
- targetClass – 真正要调用的方法所在的类
这里是有细微差别的:
- method的所属类不一样是targetClass。比如:method是代理对象的方法,它的所属类是代理出来的类
- 但是:targetClass一定会有一个方法和method的方法签名一样
通常情况下,method的所属类会是targetClass的某个祖先类或者实现的某个接口。(动态代理)
它的实现有多种:
TransactionAttributeSource一般都是作为TransactionInterceptor的一个属性被set进去,然后看看这个事务属性可以作用在不同的方法上面,实现不同方法的个性化定制~
(实际真正处理它的是父类TransactionAspectSupport,它会做匹配~~~~) 具体的在详解TransactionInterceptor的时候会讲述到
NameMatchTransactionAttributeSource
根据名字就能匹配,然后该事务属性就会作用在对应的方法上。比如下面例子:
// 自定义配置一个事务拦截器(@Transaction注解也会使用此拦截器进行拦截) @Bean public TransactionInterceptor transactionInterceptor(PlatformTransactionManager transactionManager) { Map<String, TransactionAttribute> txMap = new HashMap<>(); // required事务 适用于觉得部分场景~ RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute(); requiredTx.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(RuntimeException.class))); requiredTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); txMap.put("add*", requiredTx); txMap.put("save*", requiredTx); txMap.put("insert*", requiredTx); txMap.put("update*", requiredTx); txMap.put("delete*", requiredTx); // 查询 使用只读事务 RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute(); readOnlyTx.setReadOnly(true); readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED); txMap.put("get*", readOnlyTx); txMap.put("query*", readOnlyTx); // 定义事务属性的source~~~ 此处使用它 也就是根据方法名进行匹配的~~~ NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource(); source.setNameMap(txMap); return new TransactionInterceptor(transactionManager, source); }
这个在我们基于XML的配置事务的时候,原理就是这样的~~
注意此处的匹配模式也是基于简单匹配的:PatternMatchUtils.simpleMatch。而非强大的正则匹配。底层getTransactionAttribute()时会根据不同的方法名,来返回不同的事务属性~~~
MethodMapTransactionAttributeSource
它的使用方式和NameMatchTransactionAttributeSource基本相同,但是有一个不同在于:
如果使用NameMatchTransactionAttributeSource配置属性源,比如get*配置为执行事务,那么所有的bean的get方法都会被加上事务,这可能不是我们想要的,因此对于自动代理,我们更好的选择是MethodMapTransactionAttributeSource,它需要指定需要事务化的完整类名和方法名
CompositeTransactionAttributeSource
若看前面AOP文章的详细讲解,讲述过它ComposablePointcut:
【小家Spring】Spring AOP各个组件概述与总结【Pointcut、Advice、Advisor、Advised、TargetSource、AdvisorChainFactory…】
它代表一种组合模式。
// @since 2.0 它是Spring2.0后才推出来的 public class CompositeTransactionAttributeSource implements TransactionAttributeSource, Serializable { private final TransactionAttributeSource[] transactionAttributeSources; public CompositeTransactionAttributeSource(TransactionAttributeSource... transactionAttributeSources) { Assert.notNull(transactionAttributeSources, "TransactionAttributeSource array must not be null"); this.transactionAttributeSources = transactionAttributeSources; } // 这个实现方法也很容易。多个TransactionAttributeSource放在一起,只要任意一个匹配上就成 // 备注:若匹配上多个,请注意先后顺序就成 这里面是数组 会保持和你放入的顺序一样~~~ @Override @Nullable public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) { for (TransactionAttributeSource source : this.transactionAttributeSources) { TransactionAttribute attr = source.getTransactionAttribute(method, targetClass); if (attr != null) { return attr; } } return null; } }