聲明式事務(wù)源碼分析之EnableTransactionManagement

上節(jié)我們通過簡單的案例來熟悉了spring注解版的聲明式事務(wù)的開發(fā),其實大家可以分別測一下,當(dāng)我們不配置事務(wù)管理以及不貼注解EnableTransactionManagement時我們執(zhí)行邏輯時是否會插入記錄到數(shù)據(jù)庫中,答案不行的,注解EnableTransactionManagement的主要目的是開啟事務(wù)的功能,接下來的學(xué)習(xí)我們來圍繞它進行

EnableTransactionManagement

點進去之后發(fā)現(xiàn)此注解位于org.springframework.transaction.annotation包下,具體代碼片段如下:

@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 2147483647;

}

看到上述的代碼我相信大家都不陌生,spring 的注解開發(fā)的套路,還是給我們的容器中導(dǎo)入一個組件【TransactionManagementConfigurationSelector】,接下來的核心就是它了

TransactionManagementConfigurationSelector

簡單的說這個組件的作用是作為一個事務(wù)配置管理的選擇器來出現(xiàn)幫助我們都做了什么事,方法進去我們發(fā)下如下的代碼片段:

 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;
    }
}

其中通過傳入的參數(shù)判斷你到底是那種類型的,并為我們導(dǎo)入其對應(yīng)的組件,我們這里是PROXY此類型的,為啥這么肯定了,在我們的EnableTransactionManagement 注解類中默認(rèn)的就是它,大家可以在開頭的代碼片段中看到,是PROXY類型,這里幫我們導(dǎo)入的是AutoProxyRegistrar和ProxyTransactionManagementConfiguration這兩個組件,分別來看:

AutoProxyRegistrar

該類實現(xiàn)了ImportBeanDefinitionRegistrar接口,也就是說其主要的作用是幫我們給容器注冊其組件,接下來我們通過方法#registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) 來看幫我們注冊的具體是那個組件

  • 1.首先通過如下的代碼操作獲取當(dāng)前的當(dāng)前容器的類型【AdviceMode:屬于JDK的代理】
Object mode = candidate.get("mode");

前面我們已經(jīng)知道了是PROXY類型的,所以接著看如下的代碼片段:

 Object proxyTargetClass = candidate.get("proxyTargetClass");

 if (mode == AdviceMode.PROXY) {
                    AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                    if ((Boolean)proxyTargetClass) {
                        AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                        return;
                    }
                }

這里有兩個判斷,來看下:

  • 如果當(dāng)前獲取到了有proxyTargetClass【代理目標(biāo)對象】時,會去執(zhí)行方法AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry),很顯然我們這里是不會調(diào)用的,在我們的注解類EnableTransactionManagement中proxyTargetClass的獲取默認(rèn)就是false,代碼如下:
 boolean proxyTargetClass() default false;

所以我們直接來分析方法AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);

  @Nullable
  public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
    return registerAutoProxyCreatorIfNecessary(registry, (Object)null);
}

@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {
    return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}

從上面的代碼我們可以看到的是AutoProxyRegistrar幫我們想容器注冊了一個InfrastructureAdvisorAutoProxyCreator【基礎(chǔ)的自動代理增強創(chuàng)建器】,看到這個是不是跟我們Aop中【AspectJAwareAdvisorAutoProxyCreator】這個有點相似,其實質(zhì)是一樣的,只不過是事務(wù)中幫我們注冊的是InfrastructureAdvisorAutoProxyCreator此類型的,我們看看它的作用:

InfrastructureAdvisorAutoProxyCreator

該類位于org.springframework.aop.framework.autoproxy包下,其繼承實現(xiàn)關(guān)系如下圖所示:

InfrastructureAdvisorAutoProxyCreator.png

不難發(fā)現(xiàn)InfrastructureAdvisorAutoProxyCreator實質(zhì)也是一個【InstantiationAwareBeanPostProcessor】類型的后置處理器,那作為后置處理器的話,我們已經(jīng)清楚的知道了它的作用:

  • 幫助我們完成對象的創(chuàng)建

  • 將創(chuàng)建完成的對象進行包裝------> 返回其對應(yīng)的代理對象

  • 獲取攔截器鏈并進行相應(yīng)的轉(zhuǎn)化為一個個的攔截器

  • 利用攔截器機制進行鏈?zhǔn)降膱?zhí)行我們的目標(biāo)方法

下面的代碼是具體的注冊過程:

   @Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
        BeanDefinition apcDefinition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");
        if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
            int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
            int requiredPriority = findPriorityForClass(cls);
            if (currentPriority < requiredPriority) {
                apcDefinition.setBeanClassName(cls.getName());
            }
        }

        return null;
    } else {
        RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
        beanDefinition.setSource(source);
        beanDefinition.getPropertyValues().add("order", -2147483648);
        beanDefinition.setRole(2);
        registry.registerBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator", beanDefinition);
        return beanDefinition;
    }
}

上述就是AutoProxyRegistrar組件幫我們所做的事,接下來我們來看看另外一個組件

ProxyTransactionManagementConfiguration

該類位于org.springframework.transaction.annotation包下,其實質(zhì)也是一個配置類,該容器注冊一些組件,這些組件有 transactionAdvisor 【事務(wù)增強器】和transactionInterceptor【事務(wù)攔截器】 ,具體注冊的邏輯代碼如下:

  • transactionAdvisor 【事務(wù)增強器】
  @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;
}
  • transactionInterceptor【事務(wù)攔截器】
@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;
}

其中在注冊組件的過程中我們發(fā)現(xiàn)會有這樣一個屬性TransactionAttributeSource【事務(wù)屬性源】,同樣也是注冊進來的

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

進去方法來到AnnotationTransactionAttributeSource類【事務(wù)注解的屬性】,其中方法#AnnotationTransactionAttributeSource(boolean publicMethodsOnly)需要我們注意一點

public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
    this.publicMethodsOnly = publicMethodsOnly;
    if (!jta12Present && !ejb3Present) {
        this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
    } else {
        this.annotationParsers = new LinkedHashSet(4);
        this.annotationParsers.add(new SpringTransactionAnnotationParser());
        if (jta12Present) {
            this.annotationParsers.add(new JtaTransactionAnnotationParser());
        }

        if (ejb3Present) {
            this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
        }
    }

}

方法主要是當(dāng)前是那種類型的事務(wù)并進行解釋其對應(yīng)的事務(wù)注解信息,當(dāng)然這里用的是spring的自己的事務(wù),也就是如下代碼:

 if (!jta12Present && !ejb3Present) {
        this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
    } else {
        this.annotationParsers = new LinkedHashSet(4);
        this.annotationParsers.add(new SpringTransactionAnnotationParser());

接著我們看到是通過SpringTransactionAnnotationParser【事務(wù)注解解析器】來幫助我們解析具體的注解信息,進去來到類SpringTransactionAnnotationParser#parseTransactionAnnotation(AnnotationAttributes attributes)方法來完成事務(wù)注解的解析過程,解析之前還是有一步重要的動作來看方法

@Override
@Nullable
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
    AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
            element, Transactional.class, false, false);
    if (attributes != null) {
        return parseTransactionAnnotation(attributes);
    }
    else {
        return null;
    }
}

這段代碼很簡單,無非就是先拿到我們的注解類Transactional【事務(wù)注解】然后封裝成一個注解屬性【AnnotationAttributes 】,接著調(diào)用我們的具體解析方法,Transactional具體都有哪些屬性我們來看看:

public @interface Transactional {
@AliasFor("transactionManager")
String value() default "";

@AliasFor("value")
String transactionManager() default "";

Propagation propagation() default Propagation.REQUIRED;

Isolation isolation() default Isolation.DEFAULT;

int timeout() default -1;

boolean readOnly() default false;

Class<? extends Throwable>[] rollbackFor() default {};

String[] rollbackForClassName() default {};

Class<? extends Throwable>[] noRollbackFor() default {};

String[] noRollbackForClassName() default {};

}

上述的這些屬性我們都是可以配置的如:

@Service
public class UserService {

@Resource
private UserDao userDao;
@Transactional(propagation = Propagation.REQUIRED ,isolation = Isolation.DEFAULT,timeout = 1)
public void insert(){
    userDao.insert();
    System.out.println("插入成功....");

    int i = 10 / 0;
}

感興趣的可以自己玩玩,既然我們已經(jīng)到AnnotationTransactionAttributeSource的作用,回到我們分析的入口類ProxyTransactionManagementConfiguration

  • 我們在方法#transactionAdvisor(TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor)中

  • 給容器中注冊了一個BeanFactoryTransactionAttributeSourceAdvisor【事務(wù)增強器】

  • 接著事務(wù)增強器保存我們前面分析的事務(wù)注解信息

  • 保存事務(wù)攔截器到事務(wù)增強器中

  • 最后進行排序操作

期間我們用到了事務(wù)攔截器,那么我們來看看這事務(wù)攔截器的作用

TransactionInterceptor

該類位于org.springframework.transaction.interceptor包下,發(fā)下該類實現(xiàn)了MethodInterceptor接口,代碼片段如下:

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
public TransactionInterceptor() {
}

還記得我們在Aop目標(biāo)方法分析時,有一步就是將每一個攔截器包裝成一個MethodInterceptor類型的攔截器,其實看到這里我們的事務(wù)攔截器的跟Aop的原理是類似的,接著回到我們的TransactionInterceptor類中#invoke(MethodInvocation invocation)方法

 @Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
    Class<?> targetClass = invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null;
    Method var10001 = invocation.getMethod();
    invocation.getClass();
    return this.invokeWithinTransaction(var10001, targetClass, invocation::proceed);
}

其中方法#invokeWithinTransaction(....)執(zhí)行目標(biāo)類的,進去我們來到l類TransactionAspectSupport中的#invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, TransactionAspectSupport.InvocationCallback invocation)方法,具體看看方法做了哪些處理:

  • 首先獲取事務(wù)注解屬性
 TransactionAttributeSource tas = this.getTransactionAttributeSource();
    TransactionAttribute txAttr = tas != null ? tas.getTransactionAttribute(method, targetClass) : null;

上述只是做鋪墊,接下來我們來看重頭戲,是如何獲取我們的事務(wù)管理器的,代碼片段如下:

TransactionManager tm = this.determineTransactionManager(txAttr);

繼續(xù)跟蹤代碼來到方法#determineTransactionManager(@Nullable TransactionAttribute txAttr)

 @Nullable
protected TransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
    if (txAttr != null && this.beanFactory != null) {
        String qualifier = txAttr.getQualifier();
        if (StringUtils.hasText(qualifier)) {
            return this.determineQualifiedTransactionManager(this.beanFactory, qualifier);
        } else if (StringUtils.hasText(this.transactionManagerBeanName)) {
            return this.determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
        } else {
            TransactionManager defaultTransactionManager = this.getTransactionManager();
            if (defaultTransactionManager == null) {
                defaultTransactionManager = (TransactionManager)this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
                if (defaultTransactionManager == null) {
                    defaultTransactionManager = (TransactionManager)this.beanFactory.getBean(TransactionManager.class);
                    this.transactionManagerCache.putIfAbsent(DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
                }
            }

            return defaultTransactionManager;
        }
    } else {
        return this.getTransactionManager();
    }
}

上述代碼主要的操作是通過不同的方式去獲取我們的事務(wù)管理器實例,分別來看:

  • 1.通過注解 @Qualifier去獲取
 String qualifier = txAttr.getQualifier();
        if (StringUtils.hasText(qualifier)) {
            return this.determineQualifiedTransactionManager(this.beanFactory, qualifier);

方法進去來到具體是如何實現(xiàn)的過程:

private PlatformTransactionManager determineQualifiedTransactionManager(BeanFactory beanFactory, String qualifier) {
    PlatformTransactionManager txManager = asPlatformTransactionManager(this.transactionManagerCache.get(qualifier));
    if (txManager == null) {
        txManager = BeanFactoryAnnotationUtils.qualifiedBeanOfType(
                beanFactory, PlatformTransactionManager.class, qualifier);
        this.transactionManagerCache.putIfAbsent(qualifier, txManager);
    }
    return txManager;
}
  • 方式二:通過bean的名字去獲取
  else {
            TransactionManager defaultTransactionManager = this.getTransactionManager();
            if (defaultTransactionManager == null) {
                defaultTransactionManager = (TransactionManager)this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
                if (defaultTransactionManager == null) {
                    defaultTransactionManager = (TransactionManager)this.beanFactory.getBean(TransactionManager.class);
                    this.transactionManagerCache.putIfAbsent(DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
                }
            }

很顯然我們是自己配置的事務(wù)管理器,所以是通過方式二的去獲取事務(wù)管理器的,既然我們了解了事務(wù)管理器的獲取過程,回到我們的方法#invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, TransactionAspectSupport.InvocationCallback invocation)接著看:

  • 接著獲取我們的PlatformTransactionManager
PlatformTransactionManager ptm = this.asPlatformTransactionManager(tm);

前提是之前沒有添加指定任何transactionmanger最終會從容器中按照類型獲取一個PlatformTransactionManager

  • 最后執(zhí)行我們的目標(biāo)方法
    1. 如果是正常的情況下直接提交事務(wù)
 private Mono<Void> commitTransactionAfterReturning(@Nullable TransactionAspectSupport.ReactiveTransactionInfo txInfo) {
        if (txInfo != null && txInfo.getReactiveTransaction() != null) {
            if (TransactionAspectSupport.this.logger.isTraceEnabled()) {
                TransactionAspectSupport.this.logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
            }

            return txInfo.getTransactionManager().commit(txInfo.getReactiveTransaction());
        } else {
            return Mono.empty();
        }
    }

2.如果有異常的話,進行事務(wù)回滾

private Mono<Void> completeTransactionAfterThrowing(@Nullable TransactionAspectSupport.ReactiveTransactionInfo txInfo, Throwable ex) {
        if (txInfo != null && txInfo.getReactiveTransaction() != null) {
            if (TransactionAspectSupport.this.logger.isTraceEnabled()) {
                TransactionAspectSupport.this.logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "] after exception: " + ex);
            }

            return txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex) ? txInfo.getTransactionManager().rollback(txInfo.getReactiveTransaction()).onErrorMap((ex2) -> {
                TransactionAspectSupport.this.logger.error("Application exception overridden by rollback exception", ex);
                if (ex2 instanceof TransactionSystemException) {
                    ((TransactionSystemException)ex2).initApplicationException(ex);
                }

                return ex2;
            }) : txInfo.getTransactionManager().commit(txInfo.getReactiveTransaction()).onErrorMap((ex2) -> {
                TransactionAspectSupport.this.logger.error("Application exception overridden by commit exception", ex);
                if (ex2 instanceof TransactionSystemException) {
                    ((TransactionSystemException)ex2).initApplicationException(ex);
                }

                return ex2;
            });
        } else {
            return Mono.empty();
        }
    }

可以發(fā)現(xiàn)的是,不管是事務(wù)提交還是回滾操作,都是通過我們的事務(wù)管理器來完成,到這里我們的聲明式事務(wù)的相關(guān)源碼分析已完成

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容