Spring源码分析:声明式事务梳理

47次阅读

共计 10768 个字符,预计需要花费 27 分钟才能阅读完成。

使用注解方式简单模拟事务
样例
说明

数据源采用 c3p0
采用 JdbcTemplate 持久化
采用 Spring 事务注解

环境搭建
POM 依赖
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!– spring 提供的 jdbcTemplate 模块 –>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<!– mysql 链接驱动包 –>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
<scope>runtime</scope>
</dependency>
<!– AOP –>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
配置类
/**
* description: 声明式事务配置类,其中 @EnableTransactionManagement
* 一定要开启。
* @author 70KG
*/
@Configuration
@ComponentScan(“com.nmys.story.springCore.springaop.tx_sample”)
@EnableTransactionManagement // — 开启基于注解的事务管理
public class TxConfig {

// — 配置数据源
@Bean
public DataSource dataSource() throws Exception {
ComboPooledDataSource pool = new ComboPooledDataSource();
pool.setUser(“root”);
pool.setPassword(“root”);
pool.setDriverClass(“com.mysql.jdbc.Driver”);
pool.setJdbcUrl(“jdbc:mysql://localhost:3306/usthe?useSSL=false”);
return pool;
}

// — 加入模板
@Bean
public JdbcTemplate jdbcTemplate() throws Exception {
JdbcTemplate template = new JdbcTemplate(dataSource());
return template;
}

// — 配置事务管理器,它才是用来提交回滚事务的主导者
@Bean
public DataSourceTransactionManager txManager() throws Exception {
DataSourceTransactionManager tx = new DataSourceTransactionManager(dataSource());
return tx;
}

}
业务类
/**
* description
* @author 70KG
*/
@Service
public class TxService {

@Autowired
private TxDao txDao;

public void insertLog(){
txDao.insertSth();
}

}
<!–more–>
/**
* description
* @author 70KG
*/
@Repository
public class TxDao {
@Autowired
private JdbcTemplate jdbcTemplate;

// @Transactional 仅表明它是一个事务方法,开启事务仅有注解是不够的,还需要配置事务管理器
@Transactional
public void insertSth() {
String sql = “INSERT into sys_log (username) VALUES(?);”;
jdbcTemplate.update(sql, “lisi”);
System.out.println(“——> 插入成功 ”);
int i = 10/0;
}
}
测试类
/**
* description
* @author 70KG
*/
public class Test01 {

public static void main(String[] args) {
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(TxConfig.class);
TxService bean = app.getBean(TxService.class);
bean.insertLog();
}

}
测试结果
测试结果肯定是能正常运行的,下面试着跟一下源码。
源码分析

当容器开始启动运行的时候就会找到 @EnableTransactionManagement 注解
进入注解,发现它使用 @Import(TransactionManagementConfigurationSelector.class) 向容器中注入了这个类
跟进 TransactionManagementConfigurationSelector,发现它最终实现的是 ImportSelector 接口,这个接口可以向 IOC 容器中以 Bean 的全类名的方式注入 Bean。

源码如下,AdviceMode 在注解 @EnableTransactionManagement 默认就是 PROXY,可见它向容器中注入了两个类,分别是 AutoProxyRegistrar 和 ProxyTransactionManagementConfiguration。
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;
}
}
}
AutoProxyRegistrar
AutoProxyRegistrar 翻译过来:自动代理注册器。进入 AutoProxyRegistrar 类,截取部分源码,如下:
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
for (String annoType : annoTypes) {
AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
if (candidate == null) {
continue;
}
Object mode = candidate.get(“mode”);
Object proxyTargetClass = candidate.get(“proxyTargetClass”);
if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
Boolean.class == proxyTargetClass.getClass()) {
candidateFound = true;
if (mode == AdviceMode.PROXY) {
// — 前面的代码主要是获取注解类型,注解信息等等。
// — 主要是这个地方,如果必要的话,就向容器中注册一个自动代理创建器。
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
………..
进入 registerAutoProxyCreatorIfNecessary(registry),AopConfigUtils 类中,源码如下:
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry,
@Nullable Object source) {
// — 断言
Assert.notNull(registry, “BeanDefinitionRegistry must not be null”);
// 先判断有没有 org.springframework.aop.config.internalAutoProxyCreator
// 首次进来,肯定没有
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;
}
// — 将 cls 也就是 InfrastructureAdvisorAutoProxyCreator 包装成 RootBeanDefinition
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add(“order”, Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// — 将 beanDefinition 注册到 IOC 容器中,Bean 的
// — 名字就叫 org.springframework.aop.config.internalAutoProxyCreator
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
向容器中注入了 InfrastructureAdvisorAutoProxyCreator,进入此类,发现父类是 AbstractAdvisorAutoProxyCreator,AbstractAdvisorAutoProxyCreator 的父类是 AbstractAutoProxyCreator,AbstractAutoProxyCreator 中的方法,创建并返回了代理类,如下:
/**
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
* @see #getAdvicesAndAdvisorsForBean
*/
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
给容器中注入 InfrastructureAdvisorAutoProxyCreator 的主要作用就是,利用后置处理器机制在对象创建以后,对对象进行包装,返回一个代理对象 (增强器),代理对象执行方法,利用拦截器链进行调用。
ProxyTransactionManagementConfiguration
进入 ProxyTransactionManagementConfiguration, 部分源码如下:
// — 向容器中注入名字为 TRANSACTION_ADVISOR_BEAN_NAME 的切面
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
// — 向切面中注入注解解析器, 专门来解析事务注解的
advisor.setTransactionAttributeSource(transactionAttributeSource());
// — 向切面中注入事务的拦截器, 专门来拦截方法, 包括事务的提交以及回滚操作
advisor.setAdvice(transactionInterceptor());
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber(“order”));
}
return advisor;
}
进入 transactionAttributeSource() 注解解析器, 源码如下:
public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
this.publicMethodsOnly = publicMethodsOnly;
this.annotationParsers = new LinkedHashSet<>(2);
// — Spring 注解的解析器
this.annotationParsers.add(new SpringTransactionAnnotationParser());
if (jta12Present) {
// — jta 的解析器
this.annotationParsers.add(new JtaTransactionAnnotationParser());
}
if (ejb3Present) {
// — ejb 的解析器
this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
}
}
进入 SpringTransactionAnnotationParser(), 部分源码如下:
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
Propagation propagation = attributes.getEnum(“propagation”);
rbta.setPropagationBehavior(propagation.value());
Isolation isolation = attributes.getEnum(“isolation”);
rbta.setIsolationLevel(isolation.value());
rbta.setTimeout(attributes.getNumber(“timeout”).intValue());
rbta.setReadOnly(attributes.getBoolean(“readOnly”));
rbta.setQualifier(attributes.getString(“value”));
ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<>();
Class<?>[] rbf = attributes.getClassArray(“rollbackFor”);
for (Class<?> rbRule : rbf) {
会发现 @Transactional 中的各种属性都在这里, 这样, 注解解析器就分析完了
再来看事务的拦截器, 分析事务是如何回滚和提交的, 进入 transactionInterceptor()
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor() {
// — 事务的拦截器
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource());
if (this.txManager != null) {
// — 将事务管理器设置进去, 为了事务的提交和回滚操作
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
TransactionInterceptor 是一个实现了 MethodInterceptor 接口的类, 标志着 TransactionInterceptor 是一个方法拦截器, 进入它的 invoke() 方法
@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);
}
进入 invokeWithinTransaction()
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
TransactionAttributeSource tas = getTransactionAttributeSource();
// — 拿到事务注解信息包括事务的 qualifier 和 rollback 信息
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
// — 获取事务管理器
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
// — 事务连接点的定义信息
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// 创建并开启事务
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
// — 调用目标方法
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
// — 出现异常了, 获取事务管理器, 进行事务的回滚
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
// — 未出现异常, 也获取事务管理器则进行事务的提交
commitTransactionAfterReturning(txInfo);
return retVal;
}
………
总结
Spring 事务源码梳理

通过注解 @EnableTransactionManagement 中的 @Import(TransactionManagementConfigurationSelector.class) 给容器中导入了两个组件,分别是:AutoProxyRegistrar 和 ProxyTransactionManagementConfiguration
AutoProxyRegistrar:它是一个后置处理器,给容器中注册一个 InfrastructureAdvisorAutoProxyCreator,InfrastructureAdvisorAutoProxyCreator 利用后置处理器机制在对象创建以后,对对象进行包装,返回一个代理对象 (增强器),代理对象执行方法,利用拦截器链进行调用。
ProxyTransactionManagementConfiguration:给容器中注册事务增强器

事务增强器要用事务注解信息:AnnotationTransactionAttributeSource 来解析事务注解
事务拦截器中:transactionInterceptor(),它是一个 TransactionInterceptor( 保存了事务属性信息和事务管理器),而 TransactionInterceptor 是一个 MethodInterceptor,在目标方法执行的时候,执行拦截器链,事务拦截器 (首先获取事务相关的属性,再获取 PlatformTransactionManager,如果没有指定任何 transactionManager,最终会从容器中按照类型获取一个 PlatformTransactionManager,最后执行目标方法,如果异常,便获取到事务管理器进行回滚,如果正常,同样拿到事务管理器提交事务。

正文完
 0