Spring注解开发(五)声明式事务

先看一个简单的例子:

新建Dao类,代码如下:

@Repository
public class PersonDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void insert() {
        String sql = "insert into tb_person(personName,age) values (?,?)";
        String personName = UUID.randomUUID().toString().substring(0, 8);
        jdbcTemplate.update(sql, personName, 20);
    }
}

新建Service类,代码如下:

@Service
public class PersonService {
    @Autowired
    private PersonDao personDao;

    @Transactional
    public void insert() {
        personDao.insert();
        System.out.println("插入完成");
        int a = 10 / 0;
        System.out.println(a);
    }
}

新建配置类,代码如下:

@Configuration
@EnableTransactionManagement
@ComponentScan("com.practice.bean")
public class MainConfig {
    @Bean
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/test");
        return dataSource;
    }

    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        return jdbcTemplate;
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource());
    }
}

执行测试类,代码如下:

   @Test
    public void test01() {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        PersonService bean = applicationContext.getBean(PersonService.class);
        bean.insert();
    }

结果为:

插入完成
java.lang.ArithmeticException: / by zero

但是数据库中并没有插入数据,

去除service类insert()方法上的@Transactional注解,再次执行测试类,结果如下:

插入完成
java.lang.ArithmeticException: / by zero

依旧会报错,但是数据库中插入了一条,说明没有受到事务控制

Spring的声明式事务的处理方式和AOP类似,我们依旧从@EnableTransactionManagement注解入手。

查看源码可知:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement 

该注解为我们导入了TransactionManagementConfigurationSelector组件。

源码中的方法为:

	@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;
		}
	}

adviceMode在注解中的默认值为AdviceMode.PROXY:

AdviceMode mode() default AdviceMode.PROXY;

根据上面的方法可以看到为容器导入了AutoProxyRegistrar和ProxyTransactionManagementConfiguration:

1.AutoProxyRegistrar做了什么?

AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
---》
@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(
		BeanDefinitionRegistry registry, @Nullable Object source) {

	return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}

给容器中注册一个 InfrastructureAdvisorAutoProxyCreator 组件,可以看到该组件实现了:SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware这两个接口,和AOP的一致。所以InfrastructureAdvisorAutoProxyCreator:

  • 利用后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器)。

在创建Bean的时候调用的还是AbstractAutoProxyCreator的wrapIfNecessary方法(AOP)

先调用了下面的方法去查找当前类使用的拦截器:

Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);

根据org.springframework.transaction.config.internalTransactionAdvisor找到了BeanFactoryTransactionAttributeSourceAdvisor:

advisors.add(this.beanFactory.getBean(name, Advisor.class));

包装成MethodInterceptor并返回。

执行下面的方法:

bject proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));

最后包装成一个代理对象并返回。

  • 注入了BeanFactory;

2.ProxyTransactionManagementConfiguration做了什么?

根据源码上的@Configuration注解,我们可以看出这是一个配置类:

@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration 

2.1、给容器中注册事务增强器;

注册了BeanFactoryTransactionAttributeSourceAdvisor,并将AnnotationTransactionAttributeSource和transactionInterceptor赋值给

2.2.注册了事务属性解析器

注册了AnnotationTransactionAttributeSource,解析SPring提供的事务注解(也支持JTA1.2和EJB3的相关注解(如果存在的话)):

@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}

上述简单示例中我们根据Debug可以看出,最终是进入了注解解析器的如下方法,读取到了@Transactional的所有属性信息

this.annotationParsers = Collections.singleton(new 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"));

		List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
		for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
			rollbackRules.add(new RollbackRuleAttribute(rbRule));
		}
		for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
			rollbackRules.add(new RollbackRuleAttribute(rbRule));
		}
		for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
			rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
		}
		for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
			rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
		}
		rbta.setRollbackRules(rollbackRules);

		return rbta;
	}

2.3、注册了事务拦截器:

注册了TransactionInterceptor,实际上就是一个MethodInterceptor(和AOP的拦截器链里的一样):

@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,在目标方法执行的时候执行拦截器链;

invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);

先获取事务相关的属性,再获取PlatformTransactionManager,如果事先没有添加指定任何transactionmanger
 最终会从容器中按照类型获取一个PlatformTransactionManager,在获取目标类的joinpointIdentification,上实例此处为com.practice.bean.PersonService.insert方法,在创建事务信息。

TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);

返回的txInfo如下图:

执行目标方法:

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;

 如果异常,获取到事务管理器,利用事务管理回滚操作:

txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());

如果正常,利用事务管理器,提交事务

commitTransactionAfterReturning(txInfo);
原文地址:https://www.cnblogs.com/demo-alen/p/13547229.html