8.2-spring 事务-声明式事务(@Transactional原理)

8.2-spring 事务-声明式事务(@Transactional原理)

8.1-spring 事务-声明式事务(使用) 一文中我们了解到 spring 通过 @Transactional 注解实现事务的操作,开发者只需要关注具体业务,而事务操作是通过 spring aop 实现的,即给使用了 @Transactional 注解的类生成代理类,然后执行具体的事务操作。生成代理类后执行事务的方式和 jdbc 提供的编程式事务方式类似,可以通过 jdbc 提供的事务 这篇文章查看详情。

何时生成代理类

spring 通过 AOP 生成代理类,了解 AOP 知识之前需要了解 IOC 相关知识点。IOC 即将对象的创建和销毁交给容器管理,简单点讲可以分为以下步骤:

  1. 解析bean
  2. 注册bean
  3. 实例化bean

而 AOP 创建代理类是在实例化bean后对原有bean进行加强,一般通过 BeanPostProcessor 的后置方法 postProcessAfterInstantiation 实现。

① 解析bean并注册 BeanPostProcessor 和切点通知类

1) spring/springboot 通过 ConfigurationClassPostProcessor.parse 解析 .class 文件,查找包含 @Component、@Service 等类似注解的类,将这些类注册到容器,同时查找包含 @Import 注解的类,这里以事务注解 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 Integer.MAX_VALUE;
}

解析 @Import 具体方法在 ConfigurationClassParser 类 doProcessConfigurationClass 方法中

// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

2)找到 @Import 注解的值并实例化,这里是 TransactionManagementConfigurationSelector:

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
    public 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;
        }
    }

    private String determineTransactionAspectClass() {
        return ClassUtils.isPresent("javax.transaction.Transactional", this.getClass().getClassLoader()) ? "org.springframework.transaction.aspectj.AspectJJtaTransactionManagementConfiguration" : "org.springframework.transaction.aspectj.AspectJTransactionManagementConfiguration";
    }
}

该代码也在 processImports 方法中,实例化后调用 selectImports 方法:
在这里插入图片描述
3)调用 selectImports 方法后获取列名称返回值,这里是 AutoProxyRegistrar 和 ProxyTransactionManagementConfiguration ,再次调用 processImports 方法,
实例化 org.springframework.context.annotation.AutoProxyRegistrar(实例化后后面会用到)

解析 ProxyTransactionManagementConfiguration (后续会将里面的bean注册到容器中)
ProxyTransactionManagementConfiguration:


package org.springframework.transaction.annotation;

@Configuration(
    proxyBeanMethods = false
)
@Role(2)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
    public ProxyTransactionManagementConfiguration() {
    }

    @Bean(
        name = {"org.springframework.transaction.config.internalTransactionAdvisor"}
    )
    @Role(2)
    public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
        BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
        advisor.setTransactionAttributeSource(transactionAttributeSource);
        advisor.setAdvice(transactionInterceptor);
        if (this.enableTx != null) {
            advisor.setOrder((Integer)this.enableTx.getNumber("order"));
        }

        return advisor;
    }

    @Bean
    @Role(2)
    public TransactionAttributeSource transactionAttributeSource() {
        return new AnnotationTransactionAttributeSource();
    }

    @Bean
    @Role(2)
    public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
        TransactionInterceptor interceptor = new TransactionInterceptor();
        interceptor.setTransactionAttributeSource(transactionAttributeSource);
        if (this.txManager != null) {
            interceptor.setTransactionManager(this.txManager);
        }

        return interceptor;
    }
}

4)注册上述bean到容器
调用的是ConfigurationClassPostProcessor 类 processConfigBeanDefinitions 方法里面的 this.reader.loadBeanDefinitions(configClasses); 方法,在这个方法里会调用 AutoProxyRegistrar 的 registerBeanDefinitions 方法


这里会注册 一个 InfrastructureAdvisorAutoProxyCreator 类到容器中:

public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {
    @Nullable
    private ConfigurableListableBeanFactory beanFactory;

    public InfrastructureAdvisorAutoProxyCreator() {
    }

    protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        super.initBeanFactory(beanFactory);
        this.beanFactory = beanFactory;
    }

    protected boolean isEligibleAdvisorBean(String beanName) {
        return this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) && this.beanFactory.getBeanDefinition(beanName).getRole() == 2;
    }
}

它是一个 BeanPostProcessor 类型

② 使用 BeanPostProcessor(InfrastructureAdvisorAutoProxyCreator) 生成代理类

1) 上述 bean 注册完成后会随着 IOC 容器实例化,包括 InfrastructureAdvisorAutoProxyCreator(BeanPostProcessor,在此类 postProcessAfterInstantiation 方法生成代理类对象),BeanFactoryTransactionAttributeSourceAdvisor (@Transactional 切点和通知),TransactionInterceptor (通知的具体实现方式,即拦截后的处理操作)

2)生成代理类对象
调用 AbstractAutoProxyCreator类的 postProcessAfterInitialization 方法,

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            // 调用此方法
            return this.wrapIfNecessary(bean, beanName, cacheKey);
        }
    }

    return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    } else if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    } else if (!this.isInfrastructureClass(bean.getClass()) && !this.shouldSkip(bean.getClass(), beanName)) {
        // 在这里会判断当前类 UserService 符不符合 @Transactional 切点,
        // 由于 UserService 加了事务注解,所以 specificInterceptors 不为空,即会创建 UserService  的代理对象
        Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, (TargetSource)null);
        if (specificInterceptors != DO_NOT_PROXY) {
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            // 在此创建代理对象
            Object proxy = this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        } else {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }
    } else {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }
}

在 getAdvicesAndAdvisorsForBean 方法中会调用 TransactionAttributeSourcePointcut 类的 matches 方法判断被代理类的方法有没有加@Transactional注解,即是否符合事务的切点

@Nullable
    protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
    List<Advisor> advisors = this.findEligibleAdvisors(beanClass, beanName);
    return advisors.isEmpty() ? DO_NOT_PROXY : advisors.toArray();
}

使用事务

调用加了spring事务的方法时,spring会调用切点通知的方法,这里是 TransactionInterceptor 类的 invoke 方法

package org.springframework.transaction.interceptor;
。。。。 省略 。。。。
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
    。。。。 省略 。。。。
    @Nullable
    public Object invoke(final MethodInvocation invocation) throws Throwable {
        Class<?> targetClass = invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null;
        return this.invokeWithinTransaction(invocation.getMethod(), targetClass, new TransactionAspectSupport.CoroutinesInvocationCallback() {
            @Nullable
            public Object proceedWithInvocation() throws Throwable {
                return invocation.proceed();
            }

            public Object getTarget() {
                return invocation.getThis();
            }

            public Object[] getArguments() {
                return invocation.getArguments();
            }
        });
    }
    。。。。 省略 。。。。
}

执行事务的具体操作在其父类 TransactionAspectSupport invokeWithinTransaction 方法中


上述讲解只是列出了一些关键性的步骤,如果需要了解各个细节需要对 IOC 容器非常熟悉,强烈建议自行阅读源码,也可以通过SpringBoot源码解析(1.4)-自动装配原理(总结) 这篇文章了解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值