欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

這一次搞懂Spring事務注解的解析方式

 更新時間:2020年08月27日 09:34:05   作者:夜勿語  
這篇文章主要介紹了這一次搞懂Spring事務注解的解析方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧

前言

事務我們都知道是什么,而Spring事務就是在數(shù)據(jù)庫之上利用AOP提供聲明式事務和編程式事務幫助我們簡化開發(fā),解耦業(yè)務邏輯和系統(tǒng)邏輯。但是Spring事務原理是怎樣?事務在方法間是如何傳播的?為什么有時候事務會失效?接下來幾篇文章將重點分析Spring事務源碼,讓我們徹底搞懂Spring事務的原理。

正文

XML標簽的解析

<tx:annotation-driven transaction-manager="transactionManager"/>

配置過事務的應該都不陌生,上面這個配置就是Spring開啟事務注解(@Transactional)支持的配置,而看過我之前文章的應該知道,這個帶前綴的標簽叫自定義標簽,我在之前的文章也分析過自定義標簽的解析過程,所以這里我直接找到對應的handler:

public class TxNamespaceHandler extends NamespaceHandlerSupport {

 static final String TRANSACTION_MANAGER_ATTRIBUTE = "transaction-manager";
 static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";
 static String getTransactionManagerName(Element element) {
 return (element.hasAttribute(TRANSACTION_MANAGER_ATTRIBUTE) ?
 element.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE) : DEFAULT_TRANSACTION_MANAGER_BEAN_NAME);
 }

 @Override
 public void init() {
 registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
 registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
 registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
 }

}

可以看到對應的注解解析器就是AnnotationDrivenBeanDefinitionParser類,在該類中一定會有一個parse方法:

 public BeanDefinition parse(Element element, ParserContext parserContext) {
 registerTransactionalEventListenerFactory(parserContext);
 String mode = element.getAttribute("mode");
 if ("aspectj".equals(mode)) {
 // mode="aspectj"
 registerTransactionAspect(element, parserContext);
 if (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader())) {
 registerJtaTransactionAspect(element, parserContext);
 }
 }
 else {
 // mode="proxy"
 AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
 }
 return null;
 }

首先拿到mode屬性的值判斷是使用AspectJ生成代理還是JDK生成代理,這里我們主要看proxy模式,進入configureAutoProxyCreator方法:

 public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
 // 注冊AOP的入口類
 AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);

 String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
 if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
 Object eleSource = parserContext.extractSource(element);

 // Create the TransactionAttributeSource definition.
 // @Transactional注解的屬性封裝
 RootBeanDefinition sourceDef = new RootBeanDefinition(
  "org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
 sourceDef.setSource(eleSource);
 sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
 String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);

 // Create the TransactionInterceptor definition.
 // AOP執(zhí)行鏈
 RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
 interceptorDef.setSource(eleSource);
 interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
 // 拿到transaction-manager屬性的值
 registerTransactionManager(element, interceptorDef);
 interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
 String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);

 // Create the TransactionAttributeSourceAdvisor definition.
 RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
 advisorDef.setSource(eleSource);
 advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
 advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
 advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
 if (element.hasAttribute("order")) {
  advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
 }
 parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);

 CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
 compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
 compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
 compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));
 parserContext.registerComponent(compositeDef);
 }
 }

這里的流程比較長,但邏輯很簡單。首先來看注冊事務AOP入口類是哪個:

 public static void registerAutoProxyCreatorIfNecessary(
 ParserContext parserContext, Element sourceElement) {

 // 將優(yōu)先級更高的AOP入口類放入到IOC容器中
 BeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary(
 parserContext.getRegistry(), parserContext.extractSource(sourceElement));
 // 設置代理生成的方式以及是否緩存代理類到當前線程
 useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
 registerComponentIfNecessary(beanDefinition, parserContext);
 }

主要看registerAutoProxyCreatorIfNecessary方法:

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

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

 private static BeanDefinition registerOrEscalateApcAsRequired(
 Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

 Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

 // 判斷傳進來的類和ICO中當前存在的類哪個優(yōu)先級更高,將更高的放入IOC中
 if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
 BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
 if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
 int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
 int requiredPriority = findPriorityForClass(cls);
 if (currentPriority < requiredPriority) {
  apcDefinition.setBeanClassName(cls.getName());
 }
 }
 return null;
 }

 //把AOP入口類封裝成beanDefinition對象,要實例化
 RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
 beanDefinition.setSource(source);
 beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
 beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
 //注解aop入口類的beanName名稱 AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME
 registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
 return beanDefinition;
 }

首先判斷容器中是否已經(jīng)存在AOP入口類,如果不存在則直接創(chuàng)建InfrastructureAdvisorAutoProxyCreator的BeanDefinition對象注冊到容器中,這個類也是我上一篇文章分析的AOP入口類AbstractAutoProxyCreator的子類,再來看看其繼承關系:

你會不會疑惑,這么多子類,到底會使用哪一個呢?回到剛剛的代碼中,可以看到如果已經(jīng)存在一個入口類了,就會通過findPriorityForClass獲取兩個類的優(yōu)先級,最終就會使用優(yōu)先級更大的那個,那么它們的優(yōu)先級順序是怎樣的呢?

 private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3);

 static {
 // Set up the escalation list...
 APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
 APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
 APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
 }

 private static int findPriorityForClass(@Nullable String className) {
 // 索引即是優(yōu)先級,越大優(yōu)先級越高,IOC中只會存在一個事務AOP入口類
 for (int i = 0; i < APC_PRIORITY_LIST.size(); i++) {
 Class<?> clazz = APC_PRIORITY_LIST.get(i);
 if (clazz.getName().equals(className)) {
 return i;
 }
 }
 throw new IllegalArgumentException(
 "Class name [" + className + "] is not a known auto-proxy creator class");
 }

可以看到,InfrastructureAdvisorAutoProxyCreator是優(yōu)先級最低的,基本上不會起作用;AspectJAwareAdvisorAutoProxyCreator是當我們配置了<aop:config>標簽時會注冊,也就是xml配置的AOP的入口類;而AnnotationAwareAspectJAutoProxyCreator是當我們配置了<aop:aspectj-autoproxy>或使用@EnableAspectJAutoProxy注解時注冊,因此大部分情況下都是使用的AnnotationAwareAspectJAutoProxyCreator。

注冊完AOP的入口類后,回到configureAutoProxyCreator方法:

RootBeanDefinition sourceDef = new RootBeanDefinition(
 "org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
sourceDef.setSource(eleSource);
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String sourceName =parserContext.getReaderContext().registerWithGeneratedName(sourceDef);

AnnotationTransactionAttributeSource類的作用就是封裝事務注解@Transactional的屬性,這里需要記住其繼承體系以及熟悉該類和其父類的屬性和方法,對后面分析事物切面執(zhí)行原理有幫助:

緊接著就是創(chuàng)建了TransactionInterceptor對象,專門的事務攔截器,并且該類是MethodInterceptor的子類,看到這個應該不陌生了,我們知道AOP調用鏈在執(zhí)行過程中主要就是調用該類的invoke的方法,因此它是事務切面執(zhí)行的入口。既然有了Interceptor,那么必不可少的還應該有Advisor,而Advisor又是由Advice和Poincut組成的,這樣才能構成一個完整的切面,所以該方法后面就是創(chuàng)建這兩個對象。以上就是xml配置AOP注解支持的原理,很簡單,下面再來看看零配置又是如何實現(xiàn)的。

AOP零配置原理

使用過SpringBoot的都知道,如果需要開啟事務注解的支持,只需要一個注解就能搞定:@EnableTransactionManagement,不用再配置xml文件,這個又是怎么做到的呢?不多說,我們直接來看其源碼:

@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {

 boolean proxyTargetClass() default false;
 AdviceMode mode() default AdviceMode.PROXY;
 int order() default Ordered.LOWEST_PRECEDENCE;
}

在該注解下使用@Import導入了一個類TransactionManagementConfigurationSelector,首先該注解的作用就是導入一個類的實例到IOC容器中,你可能會說不是在類上加@Component注解就行了么,但是有些類它并不在你掃描的路徑下,而該注解依然可以將其導入進來,所以我么主要看TransactionManagementConfigurationSelector類中做了些啥:

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

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

 private String determineTransactionAspectClass() {
 return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
 TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
 TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
 }

}

可以看到在selectImports方法中返回了AutoProxyRegistrar和ProxyTransactionManagementConfiguration類,返回后會被封裝為BeanDefinition對象,那這個方法是在哪里調用的呢?這個在之前的文章中也分析過,ConfigurationClassPostProcessor類中會調用ConfigurationClassParser類的parse方法解析@Configuration、@Import、@ImportSource等注解,具體過程這里就不再贅述了。我們繼續(xù)來分別看看AutoProxyRegistrar和ProxyTransactionManagementConfiguration類:

public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
 private final Log logger = LogFactory.getLog(getClass());

 @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) {
  //注冊事務AOP的入口類InfrastructureAdvisorAutoProxyCreator,實際上這個AOP入口類起不了作用
  AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
  if ((Boolean) proxyTargetClass) {
  AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
  return;
  }
 }
 }
 }
 }
}

public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

 /*
 * 明顯是創(chuàng)建事務切面實例
 * BeanFactoryTransactionAttributeSourceAdvisor
 *
 * */
 @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();
 }

 /*
 * 創(chuàng)建事務advice
 * TransactionInterceptor
 * */
 @Bean
 @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
 public TransactionInterceptor transactionInterceptor() {
 TransactionInterceptor interceptor = new TransactionInterceptor();
 interceptor.setTransactionAttributeSource(transactionAttributeSource());
 //事務管理器要跟數(shù)據(jù)源掛鉤,所以需要自己定義
 if (this.txManager != null) {
 interceptor.setTransactionManager(this.txManager);
 }
 return interceptor;
 }

}

看到這就很清楚了,前者是注冊AOP的入口類(這里注冊的入口類依然是InfrastructureAdvisorAutoProxyCreator),后者則是創(chuàng)建事務AOP的組件的實例到IOC中,到這里相信不僅僅是對于事務的零配置,而是整個SpringBoot的零配置實現(xiàn)原理都心中有數(shù)了。

總結

本篇結合之前所學分析了事務配置解析的原理,也帶出了SpringBoot零配置實現(xiàn)的原理,下一篇就是事務的執(zhí)行調用過程。我們需要在腦海將加載、解析和調用串聯(lián)起來,從微觀到宏觀整體把握Spring,才能真正的理解Spring。

以上這篇這一次搞懂Spring事務注解的解析方式就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • Spring使用注解方式實現(xiàn)創(chuàng)建對象

    Spring使用注解方式實現(xiàn)創(chuàng)建對象

    這篇文章主要介紹了Spring使用注解方式實現(xiàn)創(chuàng)建對象,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2023-02-02
  • Spring中的事件發(fā)布機制原理解析

    Spring中的事件發(fā)布機制原理解析

    這篇文章主要介紹了Spring中的事件發(fā)布機制原理解析,當我們關心spring容器什么時候刷新,或者想在spring容器刷新的時候做一些事情,監(jiān)聽關心的事件,主要就是在ApplicationListener中寫對應的事件,需要的朋友可以參考下
    2023-11-11
  • SpringMVC @RequestBody 為null問題的排查及解決

    SpringMVC @RequestBody 為null問題的排查及解決

    這篇文章主要介紹了SpringMVC @RequestBody 為null問題的排查及解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • 關于Java兩個浮點型數(shù)字加減乘除的問題

    關于Java兩個浮點型數(shù)字加減乘除的問題

    由于浮點數(shù)在計算機中是以二進制表示的,直接進行加減乘除運算會出現(xiàn)精度誤差,想要得到精確結果,應使用BigDecimal類進行運算
    2024-10-10
  • Java動態(tài)代理詳解及實例

    Java動態(tài)代理詳解及實例

    這篇文章主要介紹了Java動態(tài)代理詳解及實例的相關資料,需要的朋友可以參考下
    2017-01-01
  • MyBatis如何使用(一)

    MyBatis如何使用(一)

    這篇文章主要介紹了MyBatis如何使用(一)的相關資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-07-07
  • Java Eclipse進行斷點調試的方法

    Java Eclipse進行斷點調試的方法

    本篇文章主要介紹了Java Eclipse進行斷點調試的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-11-11
  • 解決springboot的aop切面不起作用問題(失效的排查)

    解決springboot的aop切面不起作用問題(失效的排查)

    這篇文章主要介紹了解決springboot的aop切面不起作用問題(失效的排查),具有很好的參考價值,希望對大家有所幫助。 一起跟隨小編過來看看吧
    2020-04-04
  • Spring Boot 中的自動配置autoconfigure詳解

    Spring Boot 中的自動配置autoconfigure詳解

    這篇文章主要介紹了Spring Boot 中的自動配置autoconfigure詳解,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2024-01-01
  • springboot關于容器啟動事件總結

    springboot關于容器啟動事件總結

    在本篇文章里小編給大家整理的是一篇關于springboot容器啟動事件相關知識點,需要的朋友們學習下。
    2019-10-10

最新評論