首页 > 编程语言 >Spring 源码(七)Spring 事务源码解析

Spring 源码(七)Spring 事务源码解析

时间:2022-11-04 14:08:45浏览次数:33  
标签:事务 return Spring Object springframework bean 源码 org 解析


注册后置处理器开启对事务的支持

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

}

这里最核心的是TransactionManagementConfigurationSelector类,这个类主要的作用是通过​​ImportSelector​​​注册了​​AutoProxyRegistrar​​​和​​ProxyTransactionManagementConfiguration​​2个组件,源码如下:

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
// 注册 InfrastructureAdvisorAutoProxyCreator 后置处理器和事务管理器组件
return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}

AutoProxyRegistrar

AutoProxyRegistrar 的主要作用是将​​InfrastructureAdvisorAutoProxyCreator​​​后置处理器注册到容器,注册这个后置处理器和上一篇Spring AOP注册​​AnnotationAwareAspectJAutoProxyCreator​​​后置处理器一样,这里就不在重复说明了。InfrastructureAdvisorAutoProxyCreator 他是实现了BeanPostProcessor 接口的后置处理器,所以所有 Bean 的初始化都会调用其 ​​postProcessAfterInitialization​​方法,这个方法的实现是在其父类AbstractAutoProxyCreator类中。

ProxyTransactionManagementConfiguration

我们通过​​ProxyTransactionManagementConfiguration​​来注册事务管理器组件,这个类本身也是一个配置类。在这个配置类中我们将会注册一下三个组件:

  • BeanFactoryTransactionAttributeSourceAdvisor:事务增强器,包含了切面组件 ​​TransactionInterceptor​​​和标签解析器​​TransactionAttributeSource​
  • TransactionAttributeSource:@Transaction注解标签解析器
  • TransactionInterceptor:保存了事务属性信息,事务管理器;它本身也是一个方法拦截器,在invoke方法中进行了事务的处理。

创建代理Bean

上面我们说了所以所有 Bean 的初始化都会调用其 ​​AbstractAutoProxyCreator#postProcessAfterInitialization​​方法来完成Bean的增强,我们跟进去可以看到这段代码:

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}

可以看到生代理对象是在​​wrapIfNecessary(bean, beanName, cacheKey);​​方法中完成的,源码如下:

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {

// 如果存在建言那么久创建代理类
// 获取拦截链
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 使用拦截链创建代理对象,对原有的Bean进行增强
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}

this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}

找到拦截链的的核心方法是 ​​BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans​​方法

findAdvisorBeans:67, BeanFactoryAdvisorRetrievalHelper (org.springframework.aop.framework.autoproxy)
findCandidateAdvisors:102, AbstractAdvisorAutoProxyCreator (org.springframework.aop.framework.autoproxy)
findEligibleAdvisors:88, AbstractAdvisorAutoProxyCreator (org.springframework.aop.framework.autoproxy)
getAdvicesAndAdvisorsForBean:70, AbstractAdvisorAutoProxyCreator (org.springframework.aop.framework.autoproxy)
wrapIfNecessary:346, AbstractAutoProxyCreator (org.springframework.aop.framework.autoproxy)
postProcessAfterInitialization:298, AbstractAutoProxyCreator (org.springframework.aop.framework.autoproxy)
applyBeanPostProcessorsAfterInitialization:423, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
initializeBean:1638, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
doCreateBean:555, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
createBean:483, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
getObject:312, AbstractBeanFactory$1 (org.springframework.beans.factory.support)
getSingleton:230, DefaultSingletonBeanRegistry (org.springframework.beans.factory.support)
doGetBean:308, AbstractBeanFactory (org.springframework.beans.factory.support)
getBean:197, AbstractBeanFactory (org.springframework.beans.factory.support)
preInstantiateSingletons:761, DefaultListableBeanFactory (org.springframework.beans.factory.support)
finishBeanFactoryInitialization:867, AbstractApplicationContext (org.springframework.context.support)
refresh:543, AbstractApplicationContext (org.springframework.context.support)
<init>:84, AnnotationConfigApplicationContext (org.springframework.context.annotation)

源码如下:

public List<Advisor> findAdvisorBeans() {
// Determine list of advisor bean names, if not cached already.
String[] advisorNames = null;
synchronized (this) {
advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// 获取所有增强器的名称
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
}
if (advisorNames.length == 0) {
return new LinkedList<Advisor>();
}

List<Advisor> advisors = new LinkedList<Advisor>();
for (String name : advisorNames) {
if (isEligibleBean(name)) {
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping currently created advisor '" + name + "'");
}
}
else {
try {
// 根据名称增强器
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
...
}
}
}
// 返回拦截链
return advisors;
}

创建代理Bean的核心流程:

  1. 单例Bean初始化完成后执行后置处理器 ​​AbstractAutoProxyCreator#postProcessAfterInitialization​​方法
  2. 在容器中找​​Advisor​​​类型的所有增强器名称,这就会将与事务相关的增强器​​BeanFactoryTransactionAttributeSourceAdvisor​​找出来
  3. 根据增强器名称获取对应的实例,并生成拦截链
  4. 判断代理类型
  5. 根据不同的代理类型和拦截链创建代理对象

执行业务方法进行拦截

前面AOP说过不管理是​​JdkDynamicAopProxy​​​还是​​CglibAopProxy​​​代理,他们的执行最终都会去调用​​MethodInterceptor.invoke()​​​方法,而我们事务对应的方法拦截器是​​TransactionInterceptor​​​类。也就是说我们对事务的增强起始是在​​TransactionInterceptor​​​的​​invoke​​方法中。源码如下:

@Override
public Object invoke(final MethodInvocation invocation) throws Throwable {
...
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
@Override
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
});
}

protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
throws Throwable {

// 获取事务属性
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
// 获取事务管理器
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
// 构造方法唯一标示
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

// 声明式事务
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// 创建事务
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// 执行被增强的方法
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 异常回滚
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
// 清除信息
cleanupTransactionInfo(txInfo);
}
// 提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
// 编程式事务
...
}

从上面我们的源码可以看出,一个事务处理的标准流程:

  1. ​createTransactionIfNecessary​​创建一个事务
  2. ​invocation.proceedWithInvocation();​​执行业务方法
  3. ​completeTransactionAfterThrowing(txInfo, ex);​​如果遇到异常,事务回滚
  4. ​commitTransactionAfterReturning(txInfo);​​如果没有异常就提交事务

在创建,回滚和提交事务方法中还有的很多对嵌套事务的逻辑,比如事务的传递性,事务回滚的条件判断等,这里就不说了,有兴趣自己去跟下源码。


标签:事务,return,Spring,Object,springframework,bean,源码,org,解析
From: https://blog.51cto.com/u_15861563/5823700

相关文章

  • FutureTask 源码解析
    Future接口和实现Future接口的FutureTask类,代表异步计算的结果。FutureTask除了实现Future接口外,还实现了Runnable接口。因此,FutureTask可以交给Executor执行,也可以由调用......
  • CompletionService 源码解析
    ​​CompletionService​​​的主要作用是:按照异步任务的完成顺序,逐个获取到已经完成的异步任务。主要实现是在​​ExecutorCompletionService​​中。类图核心内部类privat......
  • Spring Boot缓存实战 Redis 设置有效时间和自动刷新缓存,时间支持在配置文件中配置
    问题描述SpringCache提供的@Cacheable注解不支持配置过期时间,还有缓存的自动刷新。我们可以通过配置CacheManneg来配置默认的过期时间和针对每个缓存容器(value)单独配置过......
  • Spring Boot缓存实战 Caffeine
    Caffeine和SpringBoot集成Caffeine是使用Java8对Guava缓存的重写版本,在SpringBoot2.0中将取代Guava。如果出现Caffeine,CaffeineCacheManager将会自动配置。使用spring.ca......
  • Spring Boot缓存实战 Redis 设置有效时间和自动刷新缓存-2
    问题上一篇​​SpringBootCache+redis设置有效时间和自动刷新缓存,时间支持在配置文件中配置​​,说了一种时间方式,直接扩展注解的Value值,如:@Override@Cacheable(value=......
  • Spring Boot缓存实战 Redis + Caffeine 实现多级缓存
    在前文我们介绍了如何使用Redis或者Caffeine来做缓存。​​SpringBoot缓存实战Redis设置有效时间和自动刷新缓存-2​​​​SpringBoot缓存实战Caffeine​​问题描述:通......
  • JAVA并发容器-ConcurrentHashMap 1.7和1.8 源码解析
    HashMap是一个线程不安全的类,在并发情况下会产生很多问题,详情可以参考​​HashMap源码解析​​;HashTable是线程安全的类,但是它使用的是synchronized来保证线程安全,线程竞争......
  • Spring Bean 的注册和注入的几种常用方式和区别
    Spring注册Bean:包扫描+组件标注注解(@Controller、@Service、@Repository、@Component),一般项目里面使用。使用@Bean注解,一般导入第三方组件的时候使用。使用@Import注解,一......
  • HashMap 源码解析
    源码学习,边看源码边加注释,边debug,边理解。基本属性常量DEFAULT_INITIAL_CAPACITY:默认数组的初始容量-必须是2的幂。MAXIMUM_CAPACITY:数组的最大容量DEFAULT_LOAD_FACTOR:哈......
  • Spring Boot 运行原理 - 实例分析(HttpEncodingAutoConfiguration)
    在了解了SpringBoot的运作原理和主要注解后,现在来简单的分析一个SpringBoot内置的自动配置功能:http的编码配置。我们在常规项目中配置Http编码的时候是在web.xml添加一......