吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1402|回复: 1
收起左侧

[Java 原创] 深入剖析Spring源码系列-Spring事务原理(上)

  [复制链接]
siegod 发表于 2023-9-2 13:04
本帖最后由 siegod 于 2023-9-2 13:06 编辑

前言

当探讨 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:
                 //默认 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事务动态代{过}{滤}理分析

pPG7IT1.png

通过上图,发现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源码分析时,再展开唠唠。

三、小结

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

免费评分

参与人数 2吾爱币 +8 热心值 +1 收起 理由
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
zhczf + 1 我很赞同!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

ma_rui888 发表于 2023-9-3 01:03
关于C#的AOP,或其他语言的AOP,能不能也介绍一下,也讲讲?
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-28 14:53

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表