一、事务管理注解使用步骤
- 使用
@EnableTransactionManagement
注解开启Spring
事务管理,相当于xml
配置中的<tx:annotation-driven/>
; - 向容器中注册
PlatformTransactionManager
事务管理器; - 使用
@Transactional
注解标注目标方法, 使得Spring
容器中的PlatformTransactionManager
事务管理器能够管理目标方法的事务;
还有些与数据连接的配置组件需要导入至容器中, 比如DataSource, JdbcTemplate…
// 配置类
@Configuration
// 开启事务管理 相当于xml配置中的<tx:annotation-driven/>
@EnableTransactionManagement
// 包扫描
@ComponentScan(basePackages = "study.bryan.spring.tx")
public class SpringTxConfig {
// 注册DataSource
@Bean
public DataSource dataSource() throws Exception {
// 这里使用的是Druid连接池, 所以需要到Druid的相关jar包
Properties properties = new Properties();
properties.put(DruidDataSourceFactory.PROP_URL, "xxx");
properties.put(DruidDataSourceFactory.PROP_USERNAME, "xxx");
properties.put(DruidDataSourceFactory.PROP_PASSWORD, "xxx");
// 需要导入mysql驱动jar包
properties.put(DruidDataSourceFactory.PROP_DRIVERCLASSNAME, "com.mysql.jdbc.Driver");
return DruidDataSourceFactory.createDataSource(properties);
}
// 不整合mybatis下 注册JdbcTemplate 用于简化操作jdbc
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
// 向容器中注册一个TransactionManager, 事务管理器
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
@Service("orderService")
public class OrderServiceImpl {
@Autowired
private OrderMapper orderMapper;
// 开启目标方法的事务管理, 可以指定事务管理器transactionManager, 指定事务传播行为propagation, 指定事务的隔离级别isolation, 指定超时时间timeout, 指定为具体异常回滚rollbackFor, 等等
@Transactional
public Integer add() {
Integer add = orderMapper.add();
int j = 1/0;
return add;
}
}
二、@EnableTransactionManagement的作用
- 使用
@Import
注解向容器注册TransactionManagementConfigurationSelector
TransactionManagementConfigurationSelector
的父类实现ImportSelector
接口并重写selectImports()
方法,Spring
会在容器启动时注册selectImports()
方法中返回的类名的Bean
信息, 源码中根据AdviceMode
代理模式返回不同的类名, 在@EnableTransactionManagement
中AdviceMode
的默认值是AdviceMode.PROXY(jdk)
, 所以TransactionManagementConfigurationSelector
类默认向容器中注册了AutoProxyRegistrar,ProxyTransactionManagementConfiguration
这两个类的Bean
信息;- 分析
AutoProxyRegistrar
类: 是一个实现ImportBeanDefinitionRegistrar
接口的类, 并重写了registerBeanDefinitions()
方法, 在此方法中可以利用BeanDefinitionRegistry
向Spring
注册Bean
信息, 这一部分其实就是SpringAOP
的部分, 只不过最终向容器注册的Bean
信息是ID
为"org.springframework.aop.config.internalAutoProxyCreator"
, 类为InfrastructureAdvisorAutoProxyCreator
的Bean
, 而SpringAop
注解启动默认注册是的AnnotationAwareAspectJAutoProxyCreator
类, 这两个类的父类都是AbstractAutoProxyCreator
,实现了BeanPostProcessor
后置处理器和Aware
接口,向容器注册InfrastructureAdvisorAutoProxyCreator
这个类后,Spring
就会在其他单例Bean
实例化初始化之后调用AbstractAutoProxyCreator.postProcessAfterInitialization()
方法为这些单例Bean
包装创建代理对象; 这就是Spring
事物管理底层其实是基于AOP
原理的原因之一;debug运行至AbstractAutoProxyCreator.postProcessAfterInitialization()
方法时可以看到,SpringAOP
为目标Bean
创建代理对象时,需要先获取所有适用目标方法的增强器(通知方法), 在事务管理中对目标方法所使用的增强器是BeanFactoryTransactionAttributeSourceAdvisor
; - 分析
ProxyTransactionManagementConfiguration
类: 此类是一个配置类, 通过@Bean
注解向IOC容器注册了BeanFactoryTransactionAttributeSourceAdvisor
(增强器),TransactionAttributeSource
(事物属性源),TransactionInterceptor
(事物拦截器);BeanFactoryTransactionAttributeSourceAdvisor
就是事物管理的增强器, 只有将其注入值IOC
容器中,Spring
在为其他Bean
实例化初始化后, 才会为Bean
创建代理对象;其中TransactionAttributeSource
中带有TransactionAnnotationParser
事物注解解析器, 就是用来解析目标方法上@Transactional
注解中各个属性值, 将这些属性值记录至TransactionAttribute
中;TransactionInterceptor
是一个MethodInterceptor
, 在目标方法执行时SpringAOP
会通过MethodInterceptor
拦截器链拦截目标方法, 调用invoke()
方法来执行各种通知方法;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
// 使用@Import向容器中注册TransactionManagementConfigurationSelector
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
...其他源码
AdviceMode mode() default AdviceMode.PROXY;
...其他源码
}
// TransactionManagementConfigurationSelector的父类实现了ImportSelector接口, 并重写selectImports()方法,Spring会在容器启动时注册selectImports()方法中返回的类名的Bean信息, 在@EnableTransactionManagement 中AdviceMode 的默认值是AdviceMode.PROXY, 所以selectImports()默认返回了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[] {determineTransactionAspectClass()};
default:
return null;
}
}
private String determineTransactionAspectClass() {
return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
}
}
// AutoProxyRegistrar 是一个实现ImportBeanDefinitionRegistrar 接口的类, 并重写了registerBeanDefinitions()方法, 在此方法中可以利用BeanDefinitionRegistry 向Spring注册Bean信息, 这一部分其实就是SpringAOP的部分, 只不过最终向容器注册的Bean信息是ID为"org.springframework.aop.config.internalAutoProxyCreator", 类为InfrastructureAdvisorAutoProxyCreator的Bean, 而SpringAop注解启动默认注册是的AnnotationAwareAspectJAutoProxyCreator类, 这两个类的父类都是AbstractAutoProxyCreator,实现了Bean后置处理器和Aware接口, 这就是Spring事物管理底层其实是基于AOP原理的原因;
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
for (String annType : annTypes) {
AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
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) {
// 在这里注册了InfrastructureAdvisorAutoProxyCreator
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
... 其他源码
}
}