第一步建源码分析调试环境,这里引用的是org.springframework4.3.12.RELEASE版本分析的,debug之前github上下载相关源码-地址
@Repository
public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public void insert(){
String sql = "INSERT INTO `tbl_user`(username,age) VALUES(?,?)";
String username = UUID.randomUUID().toString().substring(0, 5);
jdbcTemplate.update(sql, username,19);
}
}
@Service
public class UserService {
@Autowired
private UserDao userDao;
@Transactional
public void insertUser(){
userDao.insert();
//otherDao.other();xxx
System.out.println("插入完成...");
int i = 10/0;
}
}
@EnableTransactionManagement
@ComponentScan("com.atguigu.tx")
@Configuration
public class TxConfig {
//数据源
@Bean
public DataSource dataSource() throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser("root");
dataSource.setPassword("123456");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/mysql");
return dataSource;
}
//
@Bean
public JdbcTemplate jdbcTemplate() throws Exception{
//Spring对@Configuration类会特殊处理;给容器中加组件的方法,多次调用都只是从容器中找组件
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
return jdbcTemplate;
}
//注册事务管理器在容器中
@Bean
public PlatformTransactionManager transactionManager() throws Exception{
return new DataSourceTransactionManager(dataSource());
}
}
@Test
public void test01(){
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(TxConfig.class);
UserService userService = applicationContext.getBean(UserService.class);
userService.insertUser();
applicationContext.close();
}
1.EnableTransactionManagement源码分析
EnableTransactionManagement注解是开启事务的配置,进入该注解,发现同样,该注解引入了@Import注解(感觉像是套路一样),和开启自动代理的配置类似。
进入TransactionManagementConfigurationSelector类,查看其结构,发现其的父类实现了ImportSelector接口,这个接口前几篇的博客 说过,是给容器引入对象的,这个接口只有一个实现方法,方法的返回值为类名全路径的数组。
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
/**
* {@inheritDoc}
* @return {@link ProxyTransactionManagementConfiguration} or
* {@code AspectJTransactionManagementConfiguration} for {@code PROXY} and
* {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()}, respectively
*/
@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;
}
}
}
因为这个注解的AdviceMode默认为AdviceMode.PROXY,所以是默认返回AutoProxyRegistrar与ProxyTransactionManagementConfiguration这两个对象,下面来分析这两个对象
1.1 AutoProxyRegistrar
查看AutoProxyRegistrar发现,此类实现了ImportBeanDefinitionRegistrar 接口的,通过AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)实现相关自动代理创建器的创建
其实和前几篇提到的spring Aop源码中的套路类似
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
private final Log logger = LogFactory.getLog(getClass());
@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;
}
}
}
}
if (!candidateFound) {
String name = getClass().getSimpleName();
logger.warn(String.format("%s was imported but no annotations were found " +
"having both 'mode' and 'proxyTargetClass' attributes of type " +
"AdviceMode and boolean respectively. This means that auto proxy " +
"creator registration and configuration may not have occurred as " +
"intended, and components may not be proxied as expected. Check to " +
"ensure that %s has been @Import'ed on the same class where these " +
"annotations are declared; otherwise remove the import of %s " +
"altogether.", name, name, name));
}
}
}
注册了InfrastructureAdvisorAutoProxyCreator.class 对象
点开发现和AspectJAwareAdvisorAutoProxyCreator方法类似,都是AbstractAdvisorAutoProxyCreator的子类,这个就不做赘述了,可以查看文章AnnotationAwareAspectJAutoProxyCreator 源码解析
1.2 ProxyTransactionManagementConfiguration
2.调试源码
开始debug项目,从这里可以看出返回的userService是一个代理对象,按F7(step into )
进入拦截器方法,进入拦截器执行方法
简单的分析就是这样,如果有时间和有兴趣,可以多了解下里面源码
总结:
原理:
1)、@EnableTransactionManagement
利用TransactionManagementConfigurationSelector给容器中会导入组件
导入两个组件
AutoProxyRegistrar
ProxyTransactionManagementConfiguration
2)、AutoProxyRegistrar:
给容器中注册一个 InfrastructureAdvisorAutoProxyCreator 组件;
InfrastructureAdvisorAutoProxyCreator:?
利用后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用;
3)、ProxyTransactionManagementConfiguration 做了什么?
1、给容器中注册事务增强器;
1)、事务增强器要用事务注解的信息,AnnotationTransactionAttributeSource解析事务注解
2)、事务拦截器:
TransactionInterceptor;保存了事务属性信息,事务管理器;
他是一个 MethodInterceptor;
在目标方法执行的时候;
执行拦截器链;
事务拦截器:
1)、先获取事务相关的属性
2)、再获取PlatformTransactionManager,如果事先没有添加指定任何 transactionmanger最终会从容器中按照类型获取一个PlatformTransactionManager;
3)、执行目标方法
如果异常,获取到事务管理器,利用事务管理回滚操作;
如果正常,利用事务管理器,提交事务