likes
comments
collection
share

深入刨析Spring源码系列-Spring事务原理(上)

作者站长头像
站长
· 阅读数 35

当探讨 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;
}

接下来看看TransactionManagementConfigurationSelector做了什么?

TransactionManagementConfigurationSelector分析

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

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

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

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

通过这种方式,TransactionManagementConfigurationSelector 在配置过程中灵活地选择了不同代理模式来进行spring事务管理。这里先不考虑 ASPECTJ 模式,因为我们一般都是PROXY代理模式使用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.<Integer>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注解才会进行AOP代理走TransactionInterceptor事务拦截器。

AutoProxyRegistrar分析

//org.springframework.context.annotation.AutoProxyRegistrar
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    boolean candidateFound = false;
    // 获取@EnableTransactionManagement所在配置类上的注解元信息
    Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
    for (String annoType : annoTypes) {
        // 可以理解为将注解中的属性转换成一个map
        AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
        if (candidate == null) {
            continue;
        }
        // 直接从map中获取对应的属性,默认代理模式:PROXY
        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 接口,该接口常用于一些中间件/组件与spring整合时,注册整合的bean后置处理器做扩展点,以便在bean生命周期中进行扩展操作。

当定位解析 BeanDefinition时,就会触发 AutoProxyRegistrar#registerBeanDefinitions 方法。我们重点关注 AopConfigUtils#registerAutoProxyCreatorIfNecessary(registry) 注册AOP代理后置处理器

AopConfigUtils分析

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

	//...省略
     //【重点】AOP代理相关的bean后置处理器优先级
	static {
		APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
		APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
		APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
	}
	
	...省略
	
    //基于Bean的AOP代理后置处理器
	@Nullable
	public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
																	 @Nullable Object source) {

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

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

		return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
	}
	
	...省略
        
     //注册AOP代理后置处理器到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 优先级最低
				 *
				 */
                
                // 获取注册到容器中的AOP代理Bean后置处理器的优先级(List中的索引下标)
				int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
                // 获取当前AOP代理Bean后置处理器的优先级(List中的索引下标) 。例如 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静态代码顺序添加AOP代理后置处理器到List中(List下标越大的优先级越高),可以看到InfrastructureAdvisorAutoProxyCreator优先级最低,AnnotationAwareAspectJAutoProxyCreator优先级最高,也就是说InfrastructureAdvisorAutoProxyCreator是有可能会被覆盖或者无法注册的,那么同时开启AOP代理(@EnableAspectJAutoProxy) 和 事务管理(@EnableTransactionManagement)会不会存在问题呢? 答案是不会。因为 AnnotationAwareAspectJAutoProxyCreator 的作用范围更广泛,它包含了 InfrastructureAdvisorAutoProxyCreator 的功能。

AOP代理后置处理器类型:

  • InfrastructureAdvisorAutoProxyCreator:基于Bean的AOP代理。例如 实现AdviceAdvisorPointcutAopInfrastructureBean接口的bean跳过动态代理

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

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

二、Spring事务动态代理分析

深入刨析Spring源码系列-Spring事务原理(上)

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

InstantiationAwareBeanPostProcessor 提供postProcessBeforeInstantiation方法,在bean生命周期-实例化阶段进行一些前置处理。

SmartInstantiationAwareBeanPostProcessor提供了determineCandidateConstructors方法,用于推断出所有符合要求的构造函数,在bean生命周期-实例化阶段 需要明确到底使用哪个构造函数。此外 getEarlyBeanReference 方法在这个接口中也定义,它用于bean生命周期-属性填充阶段 处理循环依赖时,对目标bean进行提前暴露对象做AOP代理( @Asyn不支持循环依赖也在这)

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

//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进行实例化前置处理,判断bean是否需要进行AOP代理

  1. 类型为 AdviceAdvisorPointcutAopInfrastructureBean 的 bean 不需要被代理。
  2. 不是原始bean而是被包装过的bean也不需要被代理,例如 ScopedProxyFactoryBean

接下来,我们继续跟踪在 bean生命周期-初始化阶段 进行事务动态代理核心流程

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

@Override
public Object postProcessAfterInitialization(@Nullable 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;
}

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来创建JDK/CGLiB代理工厂
        // spring事务使用的jdk代理工厂
        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生命周期-初始化阶段,由AOP后置处理器对目标bean进行初始化后置处理。这里我们重点两个核心步骤:getAdvicesAndAdvisorsForBeancreateProxy,它们涉及到了事务通知器的匹配筛选以及AOP代理过程。

  • getAdvicesAndAdvisorsForBean

    根据文章前面分析,我们知道事务通知器(BeanFactoryTransactionAttributeSourceAdvisor)是在配置类(ProxyTransactionManagementConfiguration)中创建并注入到了 IOC 容器中,所以通过IOC容器中可以拿到我们事务通知器(BeanFactoryTransactionAttributeSourceAdvisor),然后使用事务通知器中的切点在目标bean初始化阶段匹配方法/类上是否有@Transacational,如果匹配就返回事务通知器(BeanFactoryTransactionAttributeSourceAdvisor)

  • createProxy

    首先在new 一个 ProxyFactory时,使用策略设计模式选择(JDK代理或 CGLIB代理)创建相应的代理工厂对象( ProxyFactory )进行事务的AOP代理。这些 ProxyFactory 都继承了AdvisedSupport,而AdvisedSupport主要用于缓存前面getAdvicesAndAdvisorsForBean匹配筛选出来的通知器。当事务代理对象执行时,就可以通过AdvisedSupport缓存中获取事务通知器添加到List集合中,使用集合索引下标+模板方法形成责任链去执行事务拦截器

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

三、小结


觉得有收获的小伙伴,欢迎点个赞,感谢~

转载自:https://juejin.cn/post/7269744082649726987
评论
请登录