Spring源码解析之事务管理
程序员文章站
2022-07-05 18:10:15
...
一、环境准备
基本步骤
1)引入mysql驱动,Druid连接池,jdbc依赖
2)配置类TxConfig, 注册JdbcTemplate, DruidDataSource
3)编写业务类,使用原生jdbc操作数据库
4)加入事务管理
@EnableTransactionManagement
@Transactional
注册事务管理器TransactionManager
5)调试实现回滚,int tem = 10 / 0;
当数据回滚时候,数据库自增主键会继续增长,即回滚时数据库主键也会自增
1、引入依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
</dependencies>
2、配置类TxConfig
@EnableTransactionManagement
@ComponentScan(basePackages = {"com.whf.spring.tx"})
@Configuration
public class TxConfig {
@Bean
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/demo");
dataSource.setUsername("root");
dataSource.setPassword("admin");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource());
}
@Bean
public TransactionManager transactionManager() {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource());
return transactionManager;
}
}
3、编写业务调试
service类
@Service
public class UserService{
@Autowired
private UserDao userDao;
@Transactional
@Override
public int save(User user) {
int count = userDao.save(user);
if (count > 0) {
System.out.println("成功插入数据库。。。。");
} else {
System.out.println("插入失败。。。。");
}
int tem = 10 / 0;
return count;
}
}
dao类
@Repository
public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public int save(User user) {
String sql = "insert into `user`(name, age) values(?, ?)";
int count = jdbcTemplate.update(sql, user.getName(), user.getAge());
return count;
}
}
调试类(执行结果报错,并且数据没有插入新数据则代表事务成功回滚)
public class TxDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TxConfig.class);
UserService userService = (UserService) context.getBean(UserService.class);
int ret = userService.save(new User(UUID.randomUUID().toString().substring(0, 5), 18));
System.out.println(ret);
}
}
// 报错,并且数据库没有新增则证明事务起作用了
Exception in thread "main" java.lang.ArithmeticException: / by zero
二、源码解析
1、从@EnableTransactionManagement开始分析
1、@EnableTransactionManagement
// 引入TransactionManagementConfigurationSelector
1)@Import({TransactionManagementConfigurationSelector.class})
2)TransactionManagementConfigurationSelector实现了ImportSelector.selectImports(AdviceMode adviceMode)
通过ImportSelector注册了两个类AutoProxyRegistrar和ProxyTransactionManagementConfiguration
return new String[]{AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
2、AutoProxyRegistrar和ProxyTransactionManagementConfiguration类结构分析
1)AutoProxyRegistrar implements ImportBeanDefinitionRegistrar
在实现方法registerBeanDefinitions中注册了一个bean
internalAutoProxyCreator => InfrastructureAdvisorAutoProxyCreator
后续再详细说InfrastructureAdvisorAutoProxyCreator,跟AOP代理基本是一样的原理
2)ProxyTransactionManagementConfiguration
AbstractTransactionManagementConfiguration
ImportAware
Aware
在beam初始化之前由beanPostProcessor设置一些元信息
((ImportAware) bean).setImportMetadata(importingClass);
// 后续着重分析InfrastructureAdvisorAutoProxyCreator
2、分析InfrastructureAdvisorAutoProxyCreator
1、分析类结构
InfrastructureAdvisorAutoProxyCreator
AbstractAdvisorAutoProxyCreator
AbstractAutoProxyCreator extends ProxyProcessorSupport (实现Ordered接口)
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
2、分析SmartInstantiationAwareBeanPostProcessor和BeanFactoryAware
1)SmartInstantiationAwareBeanPostProcessor
InstantiationAwareBeanPostProcessor
BeanPostProcessor
可见InfrastructureAdvisorAutoProxyCreator是一个BeanPostProcessor,具体实现是在
父类的AbstractAutoProxyCreator
2)BeanFactoryAware
Aware
在refresh方法中的初始化其余非懒加载单实例bean方法中给bean注入BeaFactory,调用栈如下
doCreateBean(beanName, mbdToUse, args);
initializeBean(beanName, exposedObject, mbd);
invokeAwareMethods(beanName, bean);
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
3、AbstractAutoProxyCreator
从上面可以看出InfrastructureAdvisorAutoProxyCreator 是一个BeanPostProcessor。那么可以从其父类AbstractAutoProxyCreator实现的BeanPostProcessor切入分析
1、再次看下该类结构
AbstractAutoProxyCreator
SmartInstantiationAwareBeanPostProcessor
InstantiationAwareBeanPostProcessor
BeanPostProcessor
可以发现核心逻辑在下面两个BeanPostProcessor的方法中,
接下来就可以根据AbstractAutoProxyCreator的这个方法的具体实现进行分析
InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
BeanPostProcessor.postProcessAfterInitialization()
4、分析AbstractAutoProxyCreator方法
上面分析的两个方法打上断点debug,postProcessBeforeInstantiation和postProcessAfterInitialization方法
1、先进入postProcessBeforeInstantiation方法
1)在创建bean实例之前先调用下面方法,给BeanPostProcessor一个机会返回一个代理对象,
也就是通过InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
resolveBeforeInstantiation(beanName, mbdToUse);
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bp instanceof InstantiationAwareBeanPostProcessor) // 类型判断
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
2)分析AbstractAutoProxyCreator.postProcessBeforeInstantiation()
// 判断是否已经进行增强处理
this.advisedBeans.containsKey(cacheKey)
// 是否基本类型(Advice、Pointcut、Advisor、AopInfrastructureBean)
isInfrastructureClass(beanClass)
// 判断是否跳过此增强逻辑
shouldSkip(Class<?> beanClass, String beanName)
// 确定给定的bean名称是否表示“原始实例”
AutoProxyUtils.isOriginalInstance(beanName, beanClass);
// 如果我们有一个自定义的TargetSource,在这里创建代理。
// 禁止对目标bean进行不必要的默认实例化:TargetSource将以自定义方式处理目标实例
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
上面返回的是 targetSource = null,这个方法到这里就直接返回null结束了。
2、进入postProcessAfterInitialization方法
// 此时bean已经实例化并且已经完成了初始化,判断是否需要包装成代理bean
wrapIfNecessary(bean, beanName, cacheKey);
1) 获取增强拦截器
getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 查找可用增强器
findEligibleAdvisors(beanClass, beanName);
// 查找所有候选增强器
findCandidateAdvisors();
// 查找能用到当前bean的增强器
findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
最终找到的是BeanFactoryTransactionAttributeSourceAdvisor,
父类有个Advice属性:private transient volatile Advice advice;
BeanFactoryTransactionAttributeSourceAdvisor中的advice为TransactionInterceptor类型
TransactionInterceptor implements MethodInterceptor(方法拦截器)
2)创建代理对象
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
// 从beanFactory获取该bean定义,标记为
if (this.beanFactory instanceof ConfigurableListableBeanFactory)
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
// ORIGINAL_TARGET_CLASS_ATTRIBUTE : org.springframework.aop.framework.autoproxy.AutoProxyUtils.originalTargetClass
beanFactory.getMergedBeanDefinition(beanName).setAttribute(ORIGINAL_TARGET_CLASS_ATTRIBUTE, targetClass);
// 创建代理工厂
ProxyFactory proxyFactory = new ProxyFactory();
// 获取增强器BeanFactoryTransactionAttributeSourceAdvisor
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
// 配置增强器到代理工厂
proxyFactory.addAdvisors(advisors);
// 获取代理对象
proxyFactory.getProxy(getProxyClassLoader());
createAopProxy().getProxy(classLoader);
// 根据是否实现接口创建JDK动态代理或Cglib动态代理
createAopProxy() => new JdkDynamicAopProxy(config);
// 通过JDK动态代理创建代理对象
JdkDynamicAopProxy.getProxy(classLoader) => Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
JdkDynamicAopProxy实现了InvocationHandler方法,在代理类执行时,最终会会执行JdkDynamicAopProxy.invoke(Object proxy, Method method, Object[] args)
5、调用代理方法
上面流程已经完成了UserService代理对象的创建,从容器中取出bean代理对象,调用标记了
@Transactional的save(User user),在调用处打上断点
1、调用代理方法(InvocationHandler.invoke())
JdkDynamicAopProxy.invoke(Object proxy, Method method, Object[] args)
1) 判断是否equals方法或hashCode方法,是的话直接执行方法
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
2)判断Mehod的Class对象是否接口或者Advised类型
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
3)获取代理增强拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);
也就是之前分析的BeanFactoryTransactionAttributeSourceAdvisor
// 封装成MehtodInvocation对象并执行proceed方法
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
4)proceed方法
// 迭代拦截器链获取拦截器知道,直到结果为-1代表全部都已找出,从最后一个开始往前执行拦截器
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 获取拦截器
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// 调用方法拦截器的invoke方法
((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this)
// 执行TransactionInterceptor拦截器(实现了MethodInterceptor接口),事务调用方法
invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
// 获取事务属性和事务管理器
TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
final TransactionManager tm = determineTransactionManager(txAttr);
// 创建事务
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
// 创建事务信息对象
TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
// 将事务信息绑定到当前线程中ThreadLocal
txInfo.bindToThread();
// 执行代理事务方法,如果抛异常则回滚,正常则清除事务信息,最后在方法返回时提交事务
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);
6、事务回滚分析
completeTransactionAfterThrowing(txInfo, ex);
// 判断事务该异常是否回滚
txInfo.transactionAttribute.rollbackOn(ex)
// 如果@Transactional注解没有配置异常回滚属性,则RuntimeException和Error类型异常都回滚
(ex instanceof RuntimeException || ex instanceof Error);
// 通过事务管理器进行回滚
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
processRollback(defStatus, false);
doRollback(status);
// 事务管理器获取Connection对象调用rollback方法进行回滚
DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject)status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
con.rollback();
上一篇: Spring的事务管理器
下一篇: spring声明式事务