文章目录
1 通过注解方式配置数据源+事务管理器+持久层框架
比较简单,直接上代码了:
package com.nrsc.springstudy.c11_Transaction01.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
/***
* @author : Sun Chuan
* @date : 2019/11/24 19:44
* Description:
*/
@Configuration
@ComponentScan(value = "com.nrsc.springstudy.c11_Transaction")
@EnableTransactionManagement //开启事务注解功能
public class C11Config01 {
//创建数据源
@Bean
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUsername("root");
dataSource.setPassword("123456");
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/nrsc-transaction?characterEncoding=utf-8&serverTimezone=GMT&useSSL=false");
return dataSource;
}
//注册事务管理器
@Bean
public PlatformTransactionManager platformTransactionManager() throws PropertyVetoException {
return new DataSourceTransactionManager(dataSource());
}
//使用jdbcTemplate持久层框架~~~之后整理Mybatis的时候这里会换成Mybatis
@Bean
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource());
}
}
2 spring事务核心组件的注册
2.1 @EnableTransactionManagement注解
《【Spring - AOP】— AOP核心后置处理器的创建过程》那篇文章讲到AOP核心后置处理器是通过注解@EnableAspectJAutoProxy
注册到Spring容器的。与AOP类似,spring事务的核心组件也是通过一个注解注入到Spring容器的,这个注解就是1中的@EnableTransactionManagement
。其源码如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
//向容器中导入TransactionManagementConfigurationSelector类
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
/***true强制使用CGLIB代理,false非强制*/
boolean proxyTargetClass() default false;
/***使用的代理模式:PROXY--JDK代理模式(默认);ASPECTJ -- ASPECTJ代理模式*/
AdviceMode mode() default AdviceMode.PROXY;
/**
* Indicate the ordering of the execution of the transaction advisor
* when multiple advices are applied at a specific joinpoint.
* <p>The default is {@link Ordered#LOWEST_PRECEDENCE}.
*/
int order() default Ordered.LOWEST_PRECEDENCE;
}
2.2 TransactionManagementConfigurationSelector类
通过2.1的源码我们又看到了Import注解 — @Import(TransactionManagementConfigurationSelector.class)
,它的作用我在前面多篇文章里介绍过,就是往IOC容器里注入TransactionManagementConfigurationSelector这个类。接下来看一下TransactionManagementConfigurationSelector的源码:
所在类:TransactionManagementConfigurationSelector
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
//向IOC容器中注入AutoProxyRegistrar和ProxyTransactionManagementConfiguration两个类
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);
}
}
可以看到该类继承了AdviceModeImportSelector,而跟进AdviceModeImportSelector源码可以发现该类实现了ImportSelector接口,在《【Spring注解】@Import》那篇文章里介绍到过,Import一个实现了ImportSelector接口的类时可以通过该类的selectImports方法批量的向IOC容器里导入单例bean —> 也就是说该类会向IOC容器里导入AutoProxyRegistrar
和ProxyTransactionManagementConfiguration
两个类。
2.3 ProxyTransactionManagementConfiguration — 三大核心组件
ProxyTransactionManagementConfiguration类其实是一个配置类,其源码如下:
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
//事务通知 --- 动态代理机制创建增强对象时的关键类
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource());
advisor.setAdvice(transactionInterceptor());
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
//事务属性源对象 --- 用于解析@Transactional注解,获取当前事务的属性对象
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
//事务拦截器 --- 可以与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;
}
}
小结:
(1)BeanFactoryTransactionAttributeSourceAdvisor 和 TransactionAttributeSource两个组件用来拦截标注了 @Transactional注解的方法、类或接口并解析该注解的属性信息,然后借助动态代理机制创建代理对象,从而完成对目标类的增强 —
说白了spring声明式事务的核心原理其实和AOP一样就是利用动态代理机制对目标对象进行代理增强,从而使其具有处理事务的能力。
(2)TransactionInterceptor组件用在目标调用过程中,它的主要功能是对目标对象进行拦截增强,使其真正具有事务的能力。
2.4 AutoProxyRegistrar — 事务核心后置处理器
AutoProxyRegistrar类主要用来导入事务核心后置处理器 — InfrastructureAdvisorAutoProxyCreator
。
这块其实和AOP核心后置处理器AnnotationAwareAspectJAutoProxyCreator
的注册和创建过程基本一致,这里不过多介绍了,有兴趣的可以 以《【Spring - AOP】— AOP核心后置处理器的创建过程》这篇文章为例,跟踪一下事务核心后置处理器的注册+创建过程。
这里简单看一下InfrastructureAdvisorAutoProxyCreator类的继承关系图:
再对比一下AnnotationAwareAspectJAutoProxyCreator类的继承关系图
可以看到两者其实有很大的相似性,比如说:
- 两者都继承了BeanPostProcessor、InstantiationAwareBeanPostProcessor接口,说明两者都是后置处理器
- 两者都继承了Order接口,说明两者注入IOC的时机是一致的
- 两者都继承了BeanFactoryAware接口,说明两者都可以直接获得BeanFactory对象
- 两者都继承了AbstractAutoProxyCreator和AbstractAdvisorAutoProxyCreator抽象类 —
从这里我发现了自己一个认识的误区,
我以前一直以为AOP的前置处理方法啥事都没做,但是事务的后置处理器也实现了InstantiationAwareBeanPostProcessor接口,并继承了AbstractAutoProxyCreator抽象类,因此它会和AOP一样调用前置处理方法,这让我意识到事情应该不止是这么简单 —下篇文章再具体说吧。
前置处理方法的入口:
所在类: AbstractAutowireCapableBeanFactory
所在方法: createBean
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
注意:
该方法虽然每次获得的bean都为null,但是该方法却并不是只遛一圈啥都不做。 — 因此《【Spring - AOP】 — 目标对象增强核心源码解读》那篇文章说前置处理方法一般不会做什么是不正确的 ::>_<::。。。
3 总结
spring利用一个@EnableTransactionManagement注解向IOC容器里导入了四个核心组件,可以概况成下图: