【spring系列】之14:spring声明式事务实现原理剖析

论坛 期权论坛 脚本     
匿名网站用户   2020-12-21 05:18   548   0

通过上一节事务环境搭建,我们知道,在搭建的5个步骤中,有两个是spring为我们提供底层去稍作配置,然后使用的,

这两个操作涉及的便是:

  • @EnableTransactionManagement
  • PlatformTransactionManager

其中,PlatformTransactionManager是底层的事务控制器,它来控制我们的整个操作时提交还是回滚等。

我们只要配置我们具体需要的事务实现即可。

@EnableTransactionManagement是真正让框架实现事务代理,拦截的核心,下面,我们通过源码来看看它的实现和工作原理。

1.@EnableTransactionManagement源码

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {

 /**
  * Indicate whether subclass-based (CGLIB) proxies are to be created ({@code true}) as
  * opposed to standard Java interface-based proxies ({@code false}). The default is
  * {@code false}. <strong>Applicable only if {@link #mode()} is set to
  * {@link AdviceMode#PROXY}</strong>.
  * <p>Note that setting this attribute to {@code true} will affect <em>all</em>
  * Spring-managed beans requiring proxying, not just those marked with
  * {@code @Transactional}. For example, other beans marked with Spring's
  * {@code @Async} annotation will be upgraded to subclass proxying at the same
  * time. This approach has no negative impact in practice unless one is explicitly
  * expecting one type of proxy vs another, e.g. in tests.
  */
 boolean proxyTargetClass() default false;

 /**
  * Indicate how transactional advice should be applied.
  * <p><b>The default is {@link AdviceMode#PROXY}.</b>
  * Please note that proxy mode allows for interception of calls through the proxy
  * only. Local calls within the same class cannot get intercepted that way; an
  * {@link Transactional} annotation on such a method within a local call will be
  * ignored since Spring's interceptor does not even kick in for such a runtime
  * scenario. For a more advanced mode of interception, consider switching this to
  * {@link AdviceMode#ASPECTJ}.
  */
 AdviceMode mode() default AdviceMode.PROXY;

 /**
  * Indicate the ordering of the execution of the transaction advisor
  * when multiple advices are applied at a specific joinpoint.
  * <p>The default is {@link Ordered#LOWEST_PRECEDENCE}.
  */
 int order() default Ordered.LOWEST_PRECEDENCE;

}

通过源码发现,他有三个属性:

proxyTargetClass:默认值为false,表示不是CGLIB代理,如果我们要强制使用CGLIB代理,将值设置为true即可

mode:默认值为PROXY,表示走代理实现事务,如果走切面拦截器实现事务,只需将其设置为ASPECTJ即可

order:默认值是Integer.MAX_VALUE,表示如果有多个切面拦截器,事务的拦截器执行优先级最低,保证其他都能执行

那为什么加上这个注解就开启了事务功能呢?我们注意到,在注解定义的时候,引入了一个TransactionManagementConfigurationSelector

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
    ....
}

也就是在spring容器中有注册了一个事务选择器插件,那这个插件又是干啥的呢?我们继续扒代码:

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

 /**
  * {@inheritDoc}
  * @return {@link ProxyTransactionManagementConfiguration} or
  * {@code AspectJTransactionManagementConfiguration} for {@code PROXY} and
  * {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()}, respectively
  */
 @Override
 protected String[] selectImports(AdviceMode adviceMode) {
  switch (adviceMode) {
   case PROXY:
    return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
   case ASPECTJ:
    return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
   default:
    return null;
  }
 }

}

一看便知,TransactionManagementConfigurationSelector又给容器注册了两个新组件:

  1. AutoProxyRegistrar
  2. ProxyTransactionManagementConfiguration

备注:这个是通过默认配置实现的,如果将adviceMode设置为ASPECTJ,那注册的组件将会是AspectJTransactionManagementConfiguration

下面我们接着研究默认注册进来的两个插件是干啥用的。

AutoProxyRegistrar

 @Override
 public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
  boolean candidateFound = false;
  Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
  for (String annoType : annoTypes) {
   AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
   if (candidate == null) {
    continue;
   }
   Object mode = candidate.get("mode");
   Object proxyTargetClass = candidate.get("proxyTargetClass");
   if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
     Boolean.class == proxyTargetClass.getClass()) {
    candidateFound = true;
    if (mode == AdviceMode.PROXY) {
     AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
     if ((Boolean) proxyTargetClass) {
      AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
      return;
     }
    }
   }
  }
  if (!candidateFound) {
   String name = getClass().getSimpleName();
   logger.warn(String.format("%s was imported but no annotations were found " +
     "having both 'mode' and 'proxyTargetClass' attributes of type " +
     "AdviceMode and boolean respectively. This means that auto proxy " +
     "creator registration and configuration may not have occurred as " +
     "intended, and components may not be proxied as expected. Check to " +
     "ensure that %s has been @Import'ed on the same class where these " +
     "annotations are declared; otherwise remove the import of %s " +
     "altogether.", name, name, name));
  }
 }

注意到以上代码中有一句很关键:AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);

 @Nullable
 public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
   @Nullable Object source) {

  return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
 }

跟踪代码,最终发现,这句话的作用就是在容器中注册了InfrastructureAdvisorAutoProxyCreator对象,那他又是干啥用的呢?

代码中有这样一句:

registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);

由此可见:InfrastructureAdvisorAutoProxyCreator利用后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用;

ProxyTransactionManagementConfiguration

 @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
 @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
 public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
  BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
  advisor.setTransactionAttributeSource(transactionAttributeSource());
  advisor.setAdvice(transactionInterceptor());
  if (this.enableTx != null) {
   advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
  }
  return advisor;
 }

上面的代码,是给容器注册了事务增强器。

 @Bean
 @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
 public TransactionAttributeSource transactionAttributeSource() {
  return new AnnotationTransactionAttributeSource();
 }

事务增强器要用事务注解的信息,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;
 }

事务拦截器:TransactionInterceptor;保存了事务属性信息,事务管理器;

他是一个 MethodInterceptor,在目标方法执行的时候,执行拦截器链。

具体的事务拦截器执行流程如下:

  1. 先获取事务相关的属性
  2. 再获取PlatformTransactionManager,如果事先没有添加指定任何transactionmanger,最终会从容器中按照类型获取一个PlatformTransactionManager;
  3. 执行目标方法 如果异常,获取到事务管理器,利用事务管理回滚操作;如果正常,利用事务管理器,提交事务

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1136255
帖子:227251
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP