准备
我们知道使用@Transactional,要满足以下条件
1、配置数据源 DataSource
2、配置事务管理器 PlatformTransactionManager
3、配置类上标识 @EnableTransactionManagement
@Configuration
@PropertySource(value = {"classpath:jdbc.properties"},encoding = "UTF-8")
public class TransactionalConfig {
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Value("${jdbc.driver}")
private String driver;
/**
* 配置数据源
* @return
*/
@Bean
public DataSource dataSource(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl(url);
druidDataSource.setUsername(username);
druidDataSource.setPassword(password);
druidDataSource.setDriverClassName(driver);
return druidDataSource;
}
/**
* 配置事务管理器
* @param dataSource
* @return
*/
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource){
DataSourceTransactionManager manager = new DataSourceTransactionManager();
manager.setDataSource(dataSource);
return manager;
}
/**
* 配置jdbcTemplate
* @param dataSource
* @return
*/
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource){
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
}
/**
* 核心配置类
*/
@Configuration
@ComponentScan({"com.xiaoxu"})
@EnableAspectJAutoProxy(exposeProxy = true) // 开启Spring对注解AOP的支持
@EnableTransactionManagement // 开启Spring对注解事务支持
public class ApplicationContextConfiguration {
}
@Transactional剖析
1、 配置类上的注解@EnableTransactionManagement ,通过@Import 引入TransactionManagementConfigurationSelector 向容器中导入组件,一个是AutoProxyRegistrar和 ProxyTransactionManagementConfiguration
2、AutoProxyRegistrar 本质上是ImportBeanDefinitonRegistar,BeanDefinitionRegistar的主要作用在于加载默认定义的BeanDefintion。
他的调用时机是 容器refresh中的 invokeBeanFactoryPostProcessor中执行,这个方法主要是通过ConfigurationClassPostProcessor 处理核心配置类,解析配置类上的注解,例如@ComponentScan,@Import实现组件扫描并注册到IOC容器中。
在解析@Import完后找到了AutoProxyRegistrar,实例化 AutoProxyRegistrar(注意:并非所有组件都会放入一级缓存,只有需要才放入),调用 registerBeanDefinitions,向容器中注入一个组件AspectJAutoProxyCreator,该组件主要实现对对象进行代理
如果有必要注册AutoProxyCreator
注册AspectjAutoProxyCreator,该组件主要实现对对象进行代理
而且 这个组件不就是 @EnbaleAspectJAutoProxy注解,向容器中注册的组件嘛。
也就是说,AutoProxyRegister和AspectJAutoProxyRegistrar 本质一样,都是向容器中注入组件AspectjAutoProxyCreator,实现对目标对象生成代理
3、ProxyTransactionManagementConfiguration 事务管理配置类
ProxyTransactionManagementConfiguration是一个配置类,注入了三个组件
1、transactionAdvisor 事务增强器,其中注入了事务属性解析器和事务拦截器
2、transactionAttributeSource事务属性解析器
3、transactionInterceptor 事务拦截器
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
// 注入事务增强器
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
// 事务增强器
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
// 向事务增强中注入属性解析器TransactionAttributeSource
advisor.setTransactionAttributeSource(transactionAttributeSource());
// 向事务增强器中设置事务拦截器TransactionInterceptor
advisor.setAdvice(transactionInterceptor());
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
// 注入事务属性解析器transactionAttributeSource
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
// 注入事务拦截器transactionInterceptor
public TransactionInterceptor transactionInterceptor() {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource());
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
4、transactionAttributeSource 事务属性解析器,实现对@Transactional的解析
创建事务属性解析器
决定事务属性解析器,来解析@Transactional
通过指定的事务解析器,解析事务注解
5、TransactionInterceptor 事务拦截器,实现对@Transactional事务方法拦截调用,如果需要调用,则调用,不需要则调用,如果没有事务,那么创建事务,并且从数据库连接池中获取连接,通过ThreadLocal放入当前线程中,并设置AutoCommit为false,然后执行目标方法,如果出现异常,进行回滚,最后提交事务
@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);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// 如果没有事务就创建事务,创建的事务,会从数据库连接池中获取连接,通过ThreadLoacl放入当前线程中,并设置connect.setAutoCommit= false
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// 调用目标方法
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 如果目标方法抛异常,那么进行回滚
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
// 如果目标方法正常运行,提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
}
总结
1、容器refresh时,调用invokeBeanFactoryPostProcessor,创建并调用ConfigurationClassPostProcessor解析核心配置类
2、通过解析核心配置类上的@EnableTransactionManagement,调用importSelect实例类中方法,将容器中注入两个重要组件 AutoProxyRegister (自动代理注册器) 和 TransactionManagementConfiguration 事务配置类
3、AutoProxyRegsiter 向容器中注入 ApsectjAutoProxyCreator ,切面自动代理创建器实现 对目标类代理
TransactionManagementConfiguration 事务管理配置类,向容器中注入三个组件
- 事务属性解析器 TransactionAttributeSource,实现对@Transactional 注解解析
- 事务拦截器 TransactionInterceptor 实现事务方法拦截
- 事务增强器,分别注入了属性解析器和拦截器
4、实例化所有BeanPostProcessor包括(AspectAutoProxyCreator)
5、对BeanDefinitionMap中剩余的所有单例Bean,进行实例化 --》 属性赋值,依赖注入 --》 XXXAware --》BeanPostProcessor before --》 bean init
--》AspectAutoProxyCreator 中对需要代理的Bean 进行代理(通过获取当前Bean的所匹配的拦截器/advisor来判断是否需要代理)
6、创建完代理对象后,将原对象,增强方法/拦截器 设置到代理对象中,将代理对象放入一级缓存
7、代理对象调用目标方法,实际上走到了对应的拦截器,拦截器判断当前方法是否是@Transactional的方法,如果是,那么创建事务,从数据库连接池中获取连接,通过ThreadLocal将conn设置到当前线程中,开启事务,设置autoCommit为false
8、调用目标方法,目标方法执行过程中,获取的connetion,也是从当前线程中获取的
9、遇见异常进行回滚
10、事务提交