前言
接着上一篇博文:
【小家Spring】从基于@Transactional全注解方式的声明式事务入手,彻底掌握Spring事务管理的原理
TransactionInterceptor作为它的增强子,扮演着增强处理Spring事务的核心角色。上篇博文篇幅有限,且为了突出TransactionInterceptor和PlatformTransactionManager的重要性,因此本文专门列专文专题讲解~
TransactionInterceptor支撑着整个事务功能的架构,逻辑还是相对复杂的,那么现在我们切入正题来分析此拦截器是如何实现事务特性的。
Spring事务三大接口回顾
在spring的事务管理高层抽象层中主要包含3个接口:
TransactionDefinition:用于描述隔离级别、超时时间、是否为只读事务和事务传播规则
TransactionStatus:代表一个事务的具体运行状态、以及还原点
PlatformTransactionManager:一个高层次的接口,包含3个方法。commit、rollback和getTramsaction
TransactionStatus
在讲解拦截器的执行过程之前,先得了解Spring抽象出来的这个接口。它表示事务的状态。
若有需要,事务代码可以使用它来检索状态信息,以编程方式请求回滚(而不是抛出导致隐式回滚的异常)
// 可以看到它继承自SavepointManager,所以它也会处理还原点 public interface TransactionStatus extends SavepointManager, Flushable { // 判断当前的事务是否是新事务 boolean isNewTransaction(); // 判断该事务里面是否含有还原点~ boolean hasSavepoint(); // Set the transaction rollback-only // 这是了这个,事务的唯一结果是进行回滚。因此如果你在外层给try catche住不让事务回滚,就会抛出你可能常见的异常: // Transaction rolled back because it has been marked as rollback-only void setRollbackOnly(); boolean isRollbackOnly(); //将基础会话刷新到数据存储 for example, all affected Hibernate/JPA sessions @Override void flush(); // Return whether this transaction is completed // 不管是commit或者rollback了都算结束了~~~ boolean isCompleted(); }
它的继承体系:
AbstractTransactionStatus
它基本上是对接口进行了一些默认实现:
// @since 1.2.3 public abstract class AbstractTransactionStatus implements TransactionStatus { // 两个标志位 private boolean rollbackOnly = false; private boolean completed = false; // 一个还原点 @Nullable private Object savepoint; // 把该属性值保存为true @Override public void setRollbackOnly() { this.rollbackOnly = true; } // 注意此处并不是直接读取 @Override public boolean isRollbackOnly() { return (isLocalRollbackOnly() || isGlobalRollbackOnly()); } public boolean isLocalRollbackOnly() { return this.rollbackOnly; } // Global这里返回false 但是子类DefaultTransactionStatus复写了此方法 public boolean isGlobalRollbackOnly() { return false; } // 啥都没做 也是由子类去实现 @Override public void flush() { } ... }
下面看看两个具体类的实现:
SimpleTransactionStatus
public class SimpleTransactionStatus extends AbstractTransactionStatus { private final boolean newTransaction; // 构造函数 public SimpleTransactionStatus() { this(true); } public SimpleTransactionStatus(boolean newTransaction) { this.newTransaction = newTransaction; } @Override public boolean isNewTransaction() { return this.newTransaction; } }
它的实现太简单了,就是标志一下事务是否是新的事务。
SimpleTransactionStatus
在Spring内部目前还没有使用场景~
DefaultTransactionStatus
public class DefaultTransactionStatus extends AbstractTransactionStatus { // 它有很多的标志位,成员变量 @Nullable private final Object transaction; // 是否是新事务 private final boolean newTransaction; // 如果为给定事务打开了新的事务同步 该值为true private final boolean newSynchronization; // 该事务是否标记为了只读 private final boolean readOnly; private final boolean debug; @Nullable private final Object suspendedResources; // 它的唯一构造函数如下: public DefaultTransactionStatus(@Nullable Object transaction, boolean newTransaction, boolean newSynchronization, boolean readOnly, boolean debug, @Nullable Object suspendedResources) { this.transaction = transaction; this.newTransaction = newTransaction; this.newSynchronization = newSynchronization; this.readOnly = readOnly; this.debug = debug; this.suspendedResources = suspendedResources; } // 直接把底层事务返回 public Object getTransaction() { Assert.state(this.transaction != null, "No transaction active"); return this.transaction; } public boolean hasTransaction() { return (this.transaction != null); } // 首先 @Override public boolean isNewTransaction() { return (hasTransaction() && this.newTransaction); } ... // 都由SmartTransactionObject去处理 该接口的实现类有: // JdbcTransactionObjectSupport和JtaTransactionObject(分布式事务) public boolean isGlobalRollbackOnly() { return ((this.transaction instanceof SmartTransactionObject) && ((SmartTransactionObject) this.transaction).isRollbackOnly()); } @Override public void flush() { if (this.transaction instanceof SmartTransactionObject) { ((SmartTransactionObject) this.transaction).flush(); } } }
该DefaultTransactionStatus是Spring默认使用的事务状态,后面会有很多的接触~
对TransactionStatus有了了解之后,现在正式进去到TransactionInterceptor里
TransactionInterceptor:事务拦截器
我们已经知道了,它是个MethodInterceptor,被事务拦截的方法最终都会执行到此增强器身上。
MethodInterceptor是个环绕通知,敲好符合我们的开启、提交、回滚事务等操作~
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable { // 构造函数: // 可议不用特殊的指定PlatformTransactionManager 事务管理器,后面会讲解自定义去获取 // 可议自己指定Properties 以及 TransactionAttributeSource public TransactionInterceptor() { } public TransactionInterceptor(PlatformTransactionManager ptm, Properties attributes) { setTransactionManager(ptm); setTransactionAttributes(attributes); } public TransactionInterceptor(PlatformTransactionManager ptm, TransactionAttributeSource tas) { setTransactionManager(ptm); setTransactionAttributeSource(tas); } // 接下来就是这个invoke方法:就是拦截的入口~ @Override @Nullable public Object invoke(MethodInvocation invocation) throws Throwable { // 获取目标类 Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null); // invokeWithinTransaction:父类TransactionAspectSupport的模板方法 // invocation::proceed本处执行完成 执行目标方法(当然可能还有其余增强器) return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed); } ... }
可以看出,真正做事情的其实还是在父类,它有一个执行事务的模版。
TransactionAspectSupport
// 通过BeanFactoryAware获取到BeanFactory // InitializingBean的afterPropertiesSet是对Bean做一些验证(经常会借助它这么来校验Bean~~~) public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean { // 这个类不允许实现Serializable接口,请注意~~ // NOTE: This class must not implement Serializable because it serves as base // class for AspectJ aspects (which are not allowed to implement Serializable)! /** * Key to use to store the default transaction manager. */ private static final Object DEFAULT_TRANSACTION_MANAGER_KEY = new Object(); // currentTransactionStatus() 方法依托于它 private static final ThreadLocal<TransactionInfo> transactionInfoHolder = new NamedThreadLocal<>("Current aspect-driven transaction"); //Subclasses can use this to return the current TransactionInfo. // Only subclasses that cannot handle all operations in one method // 注意此方法是个静态方法 并且是protected的 说明只有子类能够调用,外部并不可以~~~ @Nullable protected static TransactionInfo currentTransactionInfo() throws NoTransactionException { return transactionInfoHolder.get(); } // 外部调用此Static方法,可议获取到当前事务的状态 从而甚至可议手动来提交、回滚事务 public static TransactionStatus currentTransactionStatus() throws NoTransactionException { TransactionInfo info = currentTransactionInfo(); if (info == null || info.transactionStatus == null) { throw new NoTransactionException("No transaction aspect-managed TransactionStatus in scope"); } return info.transactionStatus; } //========================================== // 事务管理器的名称(若设置,会根据此名称去找到事务管理器~~~~) @Nullable private String transactionManagerBeanName; @Nullable private PlatformTransactionManager transactionManager; @Nullable private TransactionAttributeSource transactionAttributeSource; @Nullable private BeanFactory beanFactory; // 因为事务管理器可能也会有多个 所以此处做了一个简单的缓存~ private final ConcurrentMap<Object, PlatformTransactionManager> transactionManagerCache = new ConcurrentReferenceHashMap<>(4); public void setTransactionAttributeSource(@Nullable TransactionAttributeSource transactionAttributeSource) { this.transactionAttributeSource = transactionAttributeSource; } // 这部操作发现,若传入的为Properties 内部是实际使用的是NameMatchTransactionAttributeSource 去匹配的 // 备注:若调用了此方法 transactionAttributeSource就会被覆盖的哟 public void setTransactionAttributes(Properties transactionAttributes) { NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource(); tas.setProperties(transactionAttributes); this.transactionAttributeSource = tas; } // 若你有多种匹配策略,这也是支持的 可谓非常强大有木有~~~ public void setTransactionAttributeSources(TransactionAttributeSource... transactionAttributeSources) { this.transactionAttributeSource = new CompositeTransactionAttributeSource(transactionAttributeSources); } ... // 接下来就只剩我们最为核心的处理事务的模版方法了: //protected修饰,不允许其他包和无关类调用 @Nullable protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, final InvocationCallback invocation) throws Throwable { // 获取事务属性源~ TransactionAttributeSource tas = getTransactionAttributeSource(); // 获取该方法对应的事务属性(这个特别重要) final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null); // 这个厉害了:就是去找到一个合适的事务管理器(具体策略详见方法~~~) final PlatformTransactionManager tm = determineTransactionManager(txAttr); // 拿到目标方法唯一标识(类.方法,如service.UserServiceImpl.save) final String joinpointIdentification = methodIdentification(method, targetClass, txAttr); // 如果txAttr为空或者tm 属于非CallbackPreferringPlatformTransactionManager,执行目标增强 // 在TransactionManager上,CallbackPreferringPlatformTransactionManager实现PlatformTransactionManager接口,暴露出一个方法用于执行事务处理中的回调 if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) { // 看是否有必要创建一个事务,根据`事务传播行为`,做出相应的判断 TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); Object retVal = null; try { //回调方法执行,执行目标方法(原有的业务逻辑) retVal = invocation.proceedWithInvocation(); } catch (Throwable ex) { // 出现异常了,进行回滚(注意:并不是所有异常都会rollback的) // 备注:此处若没有事务属性 会commit 兼容编程式事务吧 completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { //清除信息 cleanupTransactionInfo(txInfo); } // 目标方法完全执行完成后,提交事务~~~ commitTransactionAfterReturning(txInfo); return retVal; } //编程式事务处理(CallbackPreferringPlatformTransactionManager) 会走这里 // 原理也差不太多,这里不做详解~~~~ else { final ThrowableHolder throwableHolder = new ThrowableHolder(); // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in. try { Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status -> { TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status); try { return invocation.proceedWithInvocation(); } catch (Throwable ex) { if (txAttr.rollbackOn(ex)) { // A RuntimeException: will lead to a rollback. if (ex instanceof RuntimeException) { throw (RuntimeException) ex; } else { throw new ThrowableHolderException(ex); } } else { // A normal return value: will lead to a commit. throwableHolder.throwable = ex; return null; } } finally { cleanupTransactionInfo(txInfo); } }); // Check result state: It might indicate a Throwable to rethrow. if (throwableHolder.throwable != null) { throw throwableHolder.throwable; } return result; } catch (ThrowableHolderException ex) { throw ex.getCause(); } catch (TransactionSystemException ex2) { if (throwableHolder.throwable != null) { logger.error("Application exception overridden by commit exception", throwableHolder.throwable); ex2.initApplicationException(throwableHolder.throwable); } throw ex2; } catch (Throwable ex2) { if (throwableHolder.throwable != null) { logger.error("Application exception overridden by commit exception", throwableHolder.throwable); } throw ex2; } } } // 从容器中找到一个事务管理器 @Nullable protected PlatformTransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) { // 如果这两个都没配置,所以肯定是手动设置了PlatformTransactionManager的,那就直接返回即可 if (txAttr == null || this.beanFactory == null) { return getTransactionManager(); } // qualifier 就在此处发挥作用了,他就相当于BeanName String qualifier = txAttr.getQualifier(); if (StringUtils.hasText(qualifier)) { // 根据此名称 以及PlatformTransactionManager.class 去容器内招 return determineQualifiedTransactionManager(this.beanFactory, qualifier); } // 若没有指定qualifier 那再看看是否指定了 transactionManagerBeanName else if (StringUtils.hasText(this.transactionManagerBeanName)) { return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName); } // 若都没指定,那就不管了。直接根据类型去容器里找 getBean(Class) // 此处:若容器内有两个PlatformTransactionManager ,那就铁定会报错啦~~~ else { PlatformTransactionManager defaultTransactionManager = getTransactionManager(); if (defaultTransactionManager == null) { defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY); if (defaultTransactionManager == null) { defaultTransactionManager = this.beanFactory.getBean(PlatformTransactionManager.class); this.transactionManagerCache.putIfAbsent( DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager); } } return defaultTransactionManager; } } // ====================================== }
不同的事务处理方式使用不同的逻辑。对于声明式事务
的处理与编程式事务
的处理,重要区别在于事务属性上,因为编程式的事务处理是不需要有事务属性的
上面处理事务的模版已经分析完成,下面单独摘出来分析一些具体的非常重要的方法。