1. 案例(注解版)
- 引入依赖 build.gradle文件:
dependencies { api(project(":spring-context")) api(project(":spring-aspects")) //引入aop&切面模块 api(project(":spring-jdbc")) //引入jdbc模块 // https://mvnrepository.com/artifact/c3p0/c3p0 implementation group: 'c3p0', name: 'c3p0', version: '0.9.1.2' // https://mvnrepository.com/artifact/mysql/mysql-connector-java implementation group: 'mysql', name: 'mysql-connector-java', version: '8.0.18' // https://mvnrepository.com/artifact/org.projectlombok/lombok compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.14' }
2.注解版配置文件
@ComponentScan("com.hsf.spring.tx")
@Configuration
@EnableTransactionManagement
public class TxConfig {
@Bean
public DataSource dataSource() throws Exception {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser("root");
dataSource.setPassword("hsfxuebao");
dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/spring_tx");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate() throws Exception {
// Spring对@Configuration类会特殊处理,给容器中加组件的方法,多次调用都只是从容器中找组件
return new JdbcTemplate(dataSource());
}
// 注册事务管理器
@Bean
public PlatformTransactionManager transactionManager() throws Exception {
return new DataSourceTransactionManager(dataSource());
}
}
3.实例类
@Repository
public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public void insert() {
String sql = "INSERT INTO user(name,age) values(?,?)";
String name = UUID.randomUUID().toString().substring(0, 5);
jdbcTemplate.update(sql, name, 19);
}
}
@Service
public class UserInfoService {
public void test() {
System.out.println("UserInfoService.test()");
}
}
@Service
public class UserService {
@Autowired
private UserDao userDao;
// 不自动注入,模拟空指针异常
private UserInfoService userInfoService;
@Transactional()
public void insertUser() {
userDao.insert();
System.out.println("插入完成");
// 模拟空指针异常
userInfoService.test();
}
}
4.测试类
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(TxConfig.class);
// 事务
UserService userService = context.getBean(UserService.class);
userService.insertUser();
}
2. @EnableTransactionManagement
我们第1小节中开始事务管理很简单,使用 @EnableTransactionManagement
注解即可。那么也就说明 @EnableTransactionManagement
是我们分析的入口了。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
很明显了 @Import(TransactionManagementConfigurationSelector.class)
指向我们去看 去看 TransactionManagementConfigurationSelector
的实现。
2.1 TransactionManagementConfigurationSelector
可以看到, TransactionManagementConfigurationSelector
间接实现了 ImportSelector
接口, ImportSelector
会根据 selectImports
返回的字符串数组(一般是类的全路径名) 通过 反射加载该类并注册到Spring容器中
。
所以我们这里必然来看一下 selectImports
方法了, ImportSelector#selectImports
的实现在其父类 AdviceModeImportSelector#selectImports
:
@Override
public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
// 获取注解类型, 这里是 EnableTransactionManagement
Class<?> annType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class);
Assert.state(annType != null, "Unresolvable type argument for AdviceModeImportSelector");
// 解析出 @EnableTransactionManagement 注解的参数
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
if (attributes == null) {
throw new IllegalArgumentException(String.format(
"@%s is not present on importing class '%s' as expected",
annType.getSimpleName(), importingClassMetadata.getClassName()));
}
// 获取mode属性。EnableTransactionManagement 默认mode = AdviceMode.PROXY
AdviceMode adviceMode = attributes.getEnum(getAdviceModeAttributeName());
// 调用 TransactionManagementConfigurationSelector#selectImports
String[] imports = selectImports(adviceMode);
if (imports == null) {
throw new IllegalArgumentException("Unknown AdviceMode: " + adviceMode);
}
return imports;
}
...
@Nullable
protected abstract String[] selectImports(AdviceMode adviceMode);
可以知道了 这里是将 protected abstract String[] selectImports(AdviceMode adviceMode);
返回的值返回给 Spring。这里我们看看在 TransactionManagementConfigurationSelector
中的 selectImports(AdviceMode adviceMode)
方法的实现。
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
@Override
protected String[] selectImports(AdviceMode adviceMode) {
// 默认值 是 PROXY。个人猜测是通过 代理模式实现事务,如果是 ASPECTJ 则是通过 ASPECTJ的方式实现,AspectJ 需要单独引入编译
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
和 ProxyTransactionManagementConfiguration
。
AutoProxyRegistrar
: 主要是注册了InfrastructureAdvisorAutoProxyCreator
自动代理创建器。而InfrastructureAdvisorAutoProxyCreator
的逻辑基本上和 Aop 的逻辑相同ProxyTransactionManagementConfiguration
: 注册了事务实现的核心 Bean,包括BeanFactoryTransactionAttributeSourceAdvisor
、TransactionAttributeSource
、TransactionInterceptor
等
3. AutoProxyRegistrar
AutoProxyRegistrar
实现了 ImportBeanDefinitionRegistrar
接口,所以我们要去看看他的 registerBeanDefinitions
方法的实现。
AutoProxyRegistrar#registerBeanDefinitions
代码如下:
@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;
}
// 获取mode、proxyTargetClass 属性
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;
// 判断如果是 Proxy 模式,也就是默认模式,注册自动代理创建器
if (mode == AdviceMode.PROXY) {
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
// 如果需要代理目标列,则强制自动代理创建者使用类代理
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
... 省略日志打印
}
在这里我们可以看到, registerBeanDefinitions
方法中解析了 事务注解
,并 注册了自动代理创建器
。这里自动代理创建器我们在Aop 源码中提到过,是Aop 创建的核心。
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)
这一步最主要的作用将自动代理创建器 InfrastructureAdvisorAutoProxyCreator
注册到了 Spring容器中。
经过数