1. 自动导入配置类
和aop自动配置一样,在/META-INF/spring.factories中配置有关transaction的有2个:
代码语言:javascript复制org.springframework.boot.autoconfigure.EnableAutoConfiguration=
...
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration
这会导致TransactionAutoConfiguration
和JtaAutoConfiguration
被加载为Bean(若不明白原因, 可见上面的《spring 自动配置》系列).
本文只分析TransactionAutoConfiguration
.
2. TransactionAutoConfiguration
该类有两个内部配置类:
- TransactionTemplateConfiguration会注入一个TransactionTemplate类型的Bean
- EnableTransactionManagementConfiguration会根据
spring.aop.proxy-target-class
的值决定注入JdkDynamicAutoProxyConfiguration还是CglibAutoProxyConfiguration. 默认情况下,生效的是前者(?).
2.1 按注解依次导入
由于注解的缘故, 会依次导致以下类发生作用:
代码语言:javascript复制@Configuration
@EnableTransactionManagement(proxyTargetClass = false)
...
public static class JdkDynamicAutoProxyConfiguration {
}
代码语言:javascript复制@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
AdviceMode mode() default AdviceMode.PROXY;
...
}
代码语言:javascript复制public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY: // 根据默认值会执行此处
return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}
最终在selectImports
方法中, 默认值adviceMode
为PROXY
, 则AutoProxyRegistrar和ProxyTransactionManagementConfiguration会被导入.
2.2 AutoProxyRegistrar
这里建议debug进行调试, 总之该类生效后, 会回调registerBeanDefinitions
函数,
在函数内:
- 遍历每个Bean, 直到找到拥有@EnableTransactionManagement且模式为
AdviceMode.PROXY
的Bean
@Override
public void registerBeanDefinitions(..) {
...
if (mode == AdviceMode.PROXY) {
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
...
}
debug发现, 注解中proxyTargetClass
为真, 则上文两个函数都要执行.
经过debug发现:
- 前者会注入注册成名为"org.springframework.aop.config.internalAutoProxyCreator", 类型为InfrastructureAdvisorAutoProxyCreator的Bean
- 后者会取出Bean, 将BeanDefinition的"proxyTargetClass"设置为真
InfrastructureAdvisorAutoProxyCreator
根据注释和观察isEligibleAdvisorBean方法的调用可知,该类负责对BeanDefinition.ROLE_INFRASTRUCTURE
基础级别的Bean进行AOP包装.
该类的运作方式在于间接实现了BeanPostProcessor接口,使得从AbstractAutoProxyCreator类中继承的postProcessAfterInitialization方法被调用, 而isEligibleAdvisorBean方法在期间起作用。
2.3 ProxyTransactionManagementConfiguration
可结合注入的组件二:ProxyTransactionManagementConfiguration 的作用是什么?阅读 该类为配置类, 会注册三个Bean:
- BeanFactoryTransactionAttributeSourceAdvisor
- TransactionAttributeSource
- TransactionInterceptor
TransactionAttributeSource 实际创建的是AnnotationTransactionAttributeSource, 用于解析@Transactional注解. 在构造函数内,
代码语言:javascript复制public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
...
this.annotationParsers = new LinkedHashSet<>(2);
this.annotationParsers.add(new SpringTransactionAnnotationParser());
...
}
会创建SpringTransactionAnnotationParser, 并用于解析@Transactional注解
代码语言:javascript复制@Nullable
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) {
for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
TransactionAttribute attr = annotationParser.parseTransactionAnnotation(ae);
if (attr != null) {
return attr;
}
}
return null;
}
其中, parseTransactionAnnotation被调用. BeanFactoryTransactionAttributeSourceAdvisor 该类依赖于2和3, 它定义了一个切面(与2相关), 也定义了一个Advisor(与3相关). TransactionInterceptor 最后是最关键的, 用于管理事务的拦截器, 该类的invoke方法会被AOP调用. AOP如何调用请自行了解AOP的原理.
代码语言:javascript复制@Override
@Nullable
public Object invoke(final MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {@code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}
代码语言:javascript复制protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
...
// If the transaction attribute is null, the method is non-transactional.
...
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
...
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); // 创建事务
Object retVal = null;
try {
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
completeTransactionAfterThrowing(txInfo, ex); // 回滚事务
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
commitTransactionAfterReturning(txInfo); // 提交事务
return retVal;
}
该方法的分析忽略, 请看原文"事务执行的具体步骤"一章.
总之, 在不进行任何指定的情况下, 默认获取PlatformTransactionManager类型的Bean用来管理事务, 一般是DataSourceTransactionManager.
TransactionInterceptor将与DataSourceTransactionManager共同完成整个事务的织入流程和管理. 其中, 管理事务创建/提交/回滚的三个方法值得研究.
3. DataSourceTransactionManager
TransactionInterceptor::createTransactionIfNecessary会一路调用到DataSourceTransactionManager::doBegin:
代码语言:javascript复制@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
Connection newCon = obtainDataSource().getConnection(); // 从连接池中获取连接
...
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
// 开启事务的关键代码
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
...
con.setAutoCommit(false);
}
prepareTransactionalConnection(con, definition);
txObject.getConnectionHolder().setTransactionActive(true);
...
// 绑定ConnectionHolder
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
}
}
catch (Throwable ex) {
if (txObject.isNewConnectionHolder()) {
DataSourceUtils.releaseConnection(con, obtainDataSource());
txObject.setConnectionHolder(null, false);
}
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}
在这里我们看到了关键的三处代码:
-
Connection newCon = obtainDataSource().getConnection();
从连接池获取连接 -
con.setAutoCommit(false);
开启事务 -
TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
绑定该连接, 该连接可以被之后使用