Spring源码解析系列Spring事务原理(上)

2023年 8月 22日 56.5k 0

当探讨 Spring 框架的事务管理机制时,我们需要深入了解其背后的工作原理。本文将从事务的注解以及动态代理机制对 Spring 事务进行深入解析。

spring版本: 5.0.2

一、@EnableTransactionManagement注解分析

通常情况下,我们在 Spring Boot 项目的启动类上添加 @EnableTransactionManagement 注解来开启事务管理:

@SpringBootApplication
@EnableTransactionManagement
public class MyApplication {

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
    
}

进入@EnableTransactionManagement看看都做了些什么?

@Import({TransactionManagementConfigurationSelector.class})
public @interface EnableTransactionManagement {
    
    //是否使用cglib代理,默认JDK代理
    boolean proxyTargetClass() default false;
    
    //代理模式
    //1. PROXY :Spring AOP
    //2. ASPECTJ:AspectJ
    AdviceMode mode() default AdviceMode.PROXY;
	
    //通知执行优先级,默认最低优先级
    int order() default Integer.MAX_VALUE;
}

上述的注解细节中,我们需要特别关注 @Import 扩展点。这个扩展点用于导入了 TransactionManagementConfigurationSelector 类。而值得注意的是,TransactionManagementConfigurationSelector 实现了 ImportSelector 接口。如果你之前看过上一篇 Spring Boot 源码解析(一)- 自动装配原理 ,那么你可能对 @Import 的概念已经有所了解,因此在这里不再详述。

接下来看看TransactionManagementConfigurationSelector做了什么?

TransactionManagementConfigurationSelector分析

protected String[] selectImports(AdviceMode adviceMode) {
        switch (adviceMode) {
            case PROXY:
                return new String[]{AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
            case ASPECTJ:
                return new String[]{this.determineTransactionAspectClass()};
            default:
                return null;
        }
    }

通过以上代码,我们可以看出根据事务管理的代理模式(PROXY 或 ASPECTJ),TransactionManagementConfigurationSelector 导入了不同的类。

  • 在 PROXY 模式下,它导入了 AutoProxyRegistrarProxyTransactionManagementConfiguration 这两个关键类。
  • 在 ASPECTJ 模式下,它导入了Aspectj特定的类。

这些导入的类在事务管理中起着重要的作用。例如,AutoProxyRegistrar 注册了基于 Bean 的 AOP 代理处理器,而 ProxyTransactionManagementConfiguration 则用于注册 Spring 事务的切面。

通过这种方式,TransactionManagementConfigurationSelector 在配置过程中灵活地选择了不同的类来适应不同的事务管理模式。这里先不考虑 ASPECTJ 模式,我们一般都是使用spring aop

ProxyTransactionManagementConfiguration分析

@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

	// 注册事务通知器
	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	// BeanDefinition的角色是一个基础设施类
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
        //事务通知器
		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
        //@Transacational解析器为切点
		advisor.setTransactionAttributeSource(transactionAttributeSource());
        //事务拦截器
		advisor.setAdvice(transactionInterceptor());
		if (this.enableTx != null) {
			advisor.setOrder(this.enableTx.getNumber("order"));
		}
		return advisor;
	}

	// 解析 @Transactional 注解的属性。
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}

	// 事务拦截器,将事务属性应用于目标方法。
	@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;
	}

ProxyTransactionManagementConfiguration是被 @Configuration 标注的配置类,它创建了事务通知器、事务注解解析器和事务拦截器。当进行AOP代理时,就会通过IOC容器获取BeanFactoryTransactionAttributeSourceAdvisor对目标bean做切点匹配,切点会通过TransactionAttributeSource去解析@Transacational注解,只有在方法@Transacational注解才会使用进行TransactionInterceptor进行AOP代理。

AutoProxyRegistrar分析

//org.springframework.context.annotation.AutoProxyRegistrar
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    boolean candidateFound = false;
    // 获取@EnableTransactionManagement所在配置类上的注解元信息
    Set annoTypes = importingClassMetadata.getAnnotationTypes();
    for (String annoType : annoTypes) {
        // 可以理解为将注解中的属性转换成一个map
        AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
        if (candidate == null) {
            continue;
        }
        // 直接从map中获取对应的属性,默认代理模式:PROXY:SpringAOP
        Object mode = candidate.get("mode");
        // proxyTargetClass,是否使用cglib代理。 默认false : JDK代理
        Object proxyTargetClass = candidate.get("proxyTargetClass");
        if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
                Boolean.class == proxyTargetClass.getClass()) {

            candidateFound = true;
            if (mode == AdviceMode.PROXY) {
                // 重点:注册一个bean后置处理器 InfrastructureAdvisorAutoProxyCreator 的 beanDefinition
                AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                if ((Boolean) proxyTargetClass) {
                    //如果为ture,使用CGlib代理
                    //设置 InfrastructureAdvisorAutoProxyCreator 的 beanDefinition属性proxyTargetClass为true
                    AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                    return;
                }
            }
        }
    }
    ...省略日志
}

AutoProxyRegistrar 实现了 ImportBeanDefinitionRegistrar 接口,该接口通常用于在各种扩展中间件/组件中注册 bean 后置处理器,以便在 bean 的生命周期中进行扩展操作。当进行 BeanDefinition 的定位和解析时,会触发 AutoProxyRegistrarregisterBeanDefinitions 方法。在这一过程中,我们应该关注 AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry) 的调用。

AopConfigUtils分析

public abstract class AopConfigUtils {
    
    //AOP bean后置处理器的唯一BeanName
    public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
			"org.springframework.aop.config.internalAutoProxyCreator";

	...省略
	static {
		APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
		APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
		APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
	}
	
	...省略
	
    //基于Bean的AOP代理Bean后置处理器
	@Nullable
	public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
																	 @Nullable Object source) {

		return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
	}
	
    //基于XML配置的AOP代理Bean后置处理器
	@Nullable
	public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
																			@Nullable Object source) {

		return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
	}
	
    //基于注解的AOP代理Bean后置处理器
	@Nullable
	public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
																					  @Nullable Object source) {

		return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
	}
	
	...省略
        
     //注册AOP代理Bean后置处理器到BeanDefinition容器
    @Nullable
	private static BeanDefinition registerOrEscalateApcAsRequired(Class cls, BeanDefinitionRegistry registry,
																  @Nullable Object source) {

		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        //只能存在一个AOP代理相关的Bean后置处理器
		//如果已经注册到BeanDefinition容器,那么进行优先级覆盖
		if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
			BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
	
			if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
                /**
				 * 开启AOP代理 @EnableAspectJAutoProxy -> AnnotationAwareAspectJAutoProxyCreator 优先级最高
				 * 开启事务管理 @EnableTransactionManagement -> InfrastructureAdvisorAutoProxyCreator 优先级最低
				 *
				 */
                
                // 获取注册到BeanDefinition容器中的AOP代理Bean后置处理器的优先级(List中的索引下标)
				int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
                // 获取当前InfrastructureAdvisorAutoProxyCreator的优先级
				int requiredPriority = findPriorityForClass(cls);
				if (currentPriority < requiredPriority) {
                    // 谁的优先级大就注册谁
					apcDefinition.setBeanClassName(cls.getName());
				}
			}
			return null;
		}

		//注册bean后置处理器beanDefinetion
		RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
		beanDefinition.setSource(source);
		beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
		beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
		return beanDefinition;
	}
}

通过registerOrEscalateApcAsRequired方法,我们发现只能注册一个AOP代理的Bean后置处理器,如果已注册AOP代理的Bean后置处理器优先级低,那么会倍覆盖掉。根据AopConfigUtils静态代码按照顺序添加到List中,下标越大优先级越高。可以看到InfrastructureAdvisorAutoProxyCreator优先级最低,AnnotationAwareAspectJAutoProxyCreator优先级最高,也就是说InfrastructureAdvisorAutoProxyCreator是有可能会被覆盖或者无法注册的,那么 有的小伙伴可能会问,如果同时开启AOP代理(@EnableAspectJAutoProxy) 和 事务管理(@EnableTransactionManagement)会不会存在问题呢? 答案是不会。因为 AnnotationAwareAspectJAutoProxyCreator 的作用范围更广泛,它包含了 InfrastructureAdvisorAutoProxyCreator 的功能。

下面是不同类型的 AOP 代理bean后置处理器:

  • InfrastructureAdvisorAutoProxyCreator:基于bean的AOP代理,例如 bean实现AdviceAdvisorPointcutAopInfrastructureBean接口

  • AspectJAwareAdvisorAutoProxyCreator:基于xml配置的AOP代理

  • AnnotationAwareAspectJAutoProxyCreator:在InfrastructureAdvisorAutoProxyCreatorAspectJAwareAdvisorAutoProxyCreator基础上,增加了对使用 @Aspect 注解声明的切面的 AOP 代理支持。

二、Spring事务动态代理分析

pPG7IT1.png

通过上图,发现InfrastructureAdvisorAutoProxyCreator实现了InstantiationAwareBeanPostProcessorSmartInstantiationAwareBeanPostProcessor接口,这两接口是做什么的呢?这里触及到bean注册IOC容器相关内容,有机会再写一篇这块内容,这里就简单概括一下它们的职责吧。

InstantiationAwareBeanPostProcessor 提供postProcessBeforeInstantiation方法,在bean生命周期的实例化阶段进行一些前置处理。SmartInstantiationAwareBeanPostProcessor则提供了determineCandidateConstructors方法,用于推断出所有符合要求的构造函数,在实例化对象的时候我们就需要明确到底使用哪个构造函数。此外 getEarlyBeanReference 方法也在这个接口中定义,它用于在循环依赖时,提前暴露对象进行AOP代理( @Aysn不支持循环依赖也在这)

这里我们重点关注bean后置处理器在实例化阶段的前置处理方法postProcessBeforeInstantiation,看看InfrastructureAdvisorAutoProxyCreator在bean生命周期的实例化阶段做了什么前置处理

//org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator

//  在不考虑通知的情况下,确认哪些Bean不需要被代理
@Override
public Object postProcessBeforeInstantiation(Class beanClass, String beanName) throws BeansException {
    //如果为FactoryBean,则在beanName添加&前缀
    Object cacheKey = getCacheKey(beanClass, beanName);
    // 如果beanName为空或者不在targetSourcedBeans集合中,表示不是从目标源获取的Bean
    if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
        // advisedBeans是一个map,其中key是BeanName,value代表了这个Bean是否需要被代理
        // 如果在advisedBeans中已经包含了该Bean,说明在bean实例化前已经标识过是否需要代理
        if (this.advisedBeans.containsKey(cacheKey)) {
            return null;
        }
        // 说明还没有对这个Bean进行处理
        // 在这里会对SpringAOP中的基础设施bean,例如实现Advice,Pointcut,Advisor接口的bean标记它们不需要被代理
        // 其次,如果这个Bean不是最原始的Bean,那么也不进行代理
        if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
            //标记该Bean不需要代理,将其放入advisedBeans,值设为false
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return null;
        }
    }

    // Create proxy here if we have a custom TargetSource.
    // Suppresses unnecessary default instantiation of the target bean:
    // The TargetSource will handle target instances in a custom fashion.
    //  如果提供了定制的TargetSource(通常不提供)
    TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
    if (targetSource != null) {
        if (StringUtils.hasLength(beanName)) {
            this.targetSourcedBeans.add(beanName);
        }
        //获取能够匹配当前bena的通知
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
        //根据通知为当前bean生成代理对象
        Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    return null;
}

上述代码作用就是在bean实例化前置处理判断bean是否需要进行AOP代理

1. 类型为 `Advice`、`Advisor`、`Pointcut`、`AopInfrastructureBean` 的 bean 不需要被代理。
2.  不是原始 bean 而是被包装过的 bean 也不需要被代理,例如 `ScopedProxyFactoryBean`。

接下来,我们将关注 bean 生命周期初始化阶段的事务 AOP 代理核心流程

//org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
    //AOP
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        //发生循环依赖的话,这个判断不会成立
        if (!this.earlyProxyReferences.contains(cacheKey)) {
            // 需要代理的话,在这里完成的代理
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    // 在postProcessBeforeInstantiation方法中可能已经完成过代理了
    // 如果已经完成代理了,那么直接返回这个代理的对象
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }
    // 在postProcessBeforeInstantiation方法中可能已经将其标记为不需要代理了
    // 这种情况下,也直接返回这个Bean
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }
    // 跟在postProcessBeforeInstantiation方法中的逻辑一样
    // 如果不需要代理,直接返回,同时在advisedBeans中标记成false
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }
    /**
     * 上述流程已在bean实例化阶段的前置方法处理过
     */

    // 获取适用于该Bean的通知
    // 说白了bean是否满足切点条件,不满足则不进行代理
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    // 如果存在通知的话,说明需要被代理
    if (specificInterceptors != DO_NOT_PROXY) {
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // 到这里创建代理,实际上底层就是new了一个ProxyFactory来创建代理的
        Object proxy = createProxy(
                bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    // 如果没有通知的话,也将这个Bean标记为不需要代理
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

在bean初始化阶段进行bean后置处理器的初始化后置处理时,我们重点两个核心步骤:getAdvicesAndAdvisorsForBeancreateProxy,它们涉及到了事务通知器的匹配筛选以及代理的创建过程。

  • getAdvicesAndAdvisorsForBean

    根据文章前面分析,我们知道事务通知器(BeanFactoryTransactionAttributeSourceAdvisor)是在配置类(ProxyTransactionManagementConfiguration)创建并注入到了 IOC 容器中,所以通过IOC容器中拿到我们事务通知器(BeanFactoryTransactionAttributeSourceAdvisor),然后依赖事务通知器中的切点匹配bena方法上是否有@Transacational,如果匹配就返回事务通知器(BeanFactoryTransactionAttributeSourceAdvisor)

  • createProxy

    首先在new 一个 ProxyFactory时,使用策略设计模式选择(JDK 动态代理或 CGLIB 代理)创建相应的代理工厂对象。这些 ProxyFactory 都继承了AdvisedSupport,根据getAdvicesAndAdvisorsForBean匹配筛选出来的通知器会缓存到AdvisedSupport,然后进行动态代理。在后续事务代理对象执行时,就可以通过AdvisedSupport获取事务通知器,最后使用责任链+模板方法方式执行事务拦截器逻辑。

这里就简单概括一下它们都做了些什么事,关于这块AOP代理核心逻辑,后续写Spring AOP源码分析时,再展开唠唠。

三、小结

通过对 Spring 事务原理的AOP 代理机制深入分析,我们了解到事务的 AOP 代理机制是 Spring 中非常重要的一环。通过bean后置处理器在 bean 的实例化阶段前置处理和初始化阶段后置进行一些扩展操作,从而实现了事务的切面逻辑。关于Spring事务拦截器内容,下一章展开分析。

觉得有收获的小伙伴,欢迎一键三连,感谢~

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论