溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Springboot中@Transactional的作用是什么

發(fā)布時間:2021-07-08 16:35:07 來源:億速云 閱讀:385 作者:Leah 欄目:大數(shù)據(jù)

這期內(nèi)容當中小編將會給大家?guī)碛嘘PSpringboot中@Transactional的作用是什么,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

摘要:

SpringBoot有多了解,其實就是看你對Spring Framework有多熟悉~ 比如SpringBoot大量的模塊裝配的設計模式,其實它屬于Spring Framework提供的能力。SpringBoot大行其道的今天,基于XML配置的Spring Framework的使用方式注定已成為過去式。注解驅(qū)動應用,面向元數(shù)據(jù)編程已然成受到越來越多開發(fā)者的偏好了,畢竟它的便捷程度、優(yōu)勢都是XML方式不可比擬的。

    @Configuration
    @ConditionalOnClass({PlatformTransactionManager.class})
    @AutoConfigureAfter({JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, Neo4jDataAutoConfiguration.class})
    @EnableConfigurationProperties({TransactionProperties.class})
    public class TransactionAutoConfiguration {
        public TransactionAutoConfiguration() {
        }
    
        @Bean
        @ConditionalOnMissingBean
        public TransactionManagerCustomizers platformTransactionManagerCustomizers(ObjectProvider<PlatformTransactionManagerCustomizer<?>> customizers) {
            return new TransactionManagerCustomizers((Collection)customizers.orderedStream().collect(Collectors.toList()));
        }
    
        @Configuration
        @ConditionalOnBean({PlatformTransactionManager.class})
        @ConditionalOnMissingBean({AbstractTransactionManagementConfiguration.class})
        public static class EnableTransactionManagementConfiguration {
            public EnableTransactionManagementConfiguration() {
            }
    
            @Configuration
            @EnableTransactionManagement(
                proxyTargetClass = true
            )
            @ConditionalOnProperty(
                prefix = "spring.aop",
                name = {"proxy-target-class"},
                havingValue = "true",
                matchIfMissing = true
            )
          //默認采用cglib代理
            public static class CglibAutoProxyConfiguration {
                public CglibAutoProxyConfiguration() {
                }
            }
    
            @Configuration
            @EnableTransactionManagement(
                proxyTargetClass = false
            )
            @ConditionalOnProperty(
                prefix = "spring.aop",
                name = {"proxy-target-class"},
                havingValue = "false",
                matchIfMissing = false
            )
            public static class JdkDynamicAutoProxyConfiguration {
                public JdkDynamicAutoProxyConfiguration() {
                }
            }
        }
    
        @Configuration
      //當PlatformTransactionManager類型的bean存在并且當存在多個bean時指定為Primary的 PlatformTransactionManager存在時,該配置類才進行解析
        @ConditionalOnSingleCandidate(PlatformTransactionManager.class)
        public static class TransactionTemplateConfiguration {
            private final PlatformTransactionManager transactionManager;
    
            public TransactionTemplateConfiguration(PlatformTransactionManager transactionManager) {
                this.transactionManager = transactionManager;
            }
    
         // 由于TransactionAutoConfiguration是在DataSourceTransactionManagerAutoConfiguration之后才被解析處理的,而在DataSourceTransactionManagerAutoConfiguration中配置了transactionManager,因此, TransactionTemplateConfiguration 會被處理.
            @Bean
            @ConditionalOnMissingBean
            public TransactionTemplate transactionTemplate() {
                return new TransactionTemplate(this.transactionManager);
            }
        }
    }
PlatformTransactionManager后續(xù)章節(jié)會分析

**提示:**使用@EnableTransactionManagement注解前,請務必保證你已經(jīng)配置了至少一個PlatformTransactionManager的Bean,否則會報錯。(當然你也可以實現(xiàn)TransactionManagementConfigurer來提供一個專屬的,只是我們一般都不這么去做~~~)

開啟注解驅(qū)動
    @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;
    }

簡直和@EnableAsync注解的一模一樣。不同之處只在于@Import導入器導入的這個類.

對比一下

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(AsyncConfigurationSelector.class)
    public @interface EnableAsync {
    	// 支持自定義注解類型 去支持異步~~~
    	Class<? extends Annotation> annotation() default Annotation.class;
    	boolean proxyTargetClass() default false;
    	AdviceMode mode() default AdviceMode.PROXY;
    	int order() default Ordered.LOWEST_PRECEDENCE;
    }
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";
        }
    }

依然可以看出和@EnableAsync導入的AsyncConfigurationSelector如出一轍,都繼承自AdviceModeImportSelector,畢竟模式一樣,觸類旁通,一通百通~

AdviceModeImportSelector目前所知的三個子類是:AsyncConfigurationSelector、TransactionManagementConfigurationSelector、CachingConfigurationSelector。由此可見后面還會著重分析的Spring的緩存體系@EnableCaching,模式也是和這個極其類似的~~~

AutoProxyRegistrar

它是個ImportBeanDefinitionRegistrar,可以實現(xiàn)自己向容器里注冊Bean的定義信息

    // @since 3.1
    public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
        private final Log logger = LogFactory.getLog(this.getClass());
    
        public AutoProxyRegistrar() {
        }
    
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            boolean candidateFound = false;
          	// 這里面需要特別注意的是:這里是拿到所有的注解類型~~~而不是只拿@EnableAspectJAutoProxy這個類型的
    		// 原因:因為mode、proxyTargetClass等屬性會直接影響到代理得方式,而擁有這些屬性的注解至少有:
    		// @EnableTransactionManagement、@EnableAsync、@EnableCaching等~~~~
    		// 甚至還有啟用AOP的注解:@EnableAspectJAutoProxy它也能設置`proxyTargetClass`這個屬性的值,因此也會產(chǎn)生關聯(lián)影響~
            Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
            Iterator var5 = annTypes.iterator();
    
            while(var5.hasNext()) {
                String annType = (String)var5.next();
                AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
                if (candidate != null) {
                    Object mode = candidate.get("mode");
                    Object proxyTargetClass = candidate.get("proxyTargetClass");
                  // 如果存在mode且存在proxyTargetClass 屬性
    			// 并且兩個屬性的class類型也是對的,才會進來此處(因此其余注解相當于都擋外面了~)
                    if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() && Boolean.class == proxyTargetClass.getClass()) {
                        candidateFound = true;
                        if (mode == AdviceMode.PROXY) {
                          
    					// 它主要是注冊了一個`internalAutoProxyCreator`,但是若出現(xiàn)多次的話,這里不是覆蓋的形式,而是以優(yōu)先級的形式
                            AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                          //看要不要強制使用CGLIB的方式(由此可以發(fā)現(xiàn)  這個屬性若出現(xiàn)多次,是會是覆蓋的形式)
                            if ((Boolean)proxyTargetClass) {
                                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                                return;
                            }
                        }
                    }
                }
            }
    
            if (!candidateFound && this.logger.isInfoEnabled()) {
                String name = this.getClass().getSimpleName();
                this.logger.info(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的源碼你會發(fā)現(xiàn),事務這塊向容器注入的是一個InfrastructureAdvisorAutoProxyCreator,并且看看是采用CGLIB還是JDK代理。它主要是讀取Advisor類,并對符合的bean進行二次代理。

ProxyTransactionManagementConfiguration
    @Configuration
    public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
        public ProxyTransactionManagementConfiguration() {
        }
    
        @Bean(
            name = {"org.springframework.transaction.config.internalTransactionAdvisor"}
        )
        @Role(2)
        public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
            BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
            advisor.setTransactionAttributeSource(this.transactionAttributeSource());
            advisor.setAdvice(this.transactionInterceptor());
            if (this.enableTx != null) {
              // 順序由@EnableTransactionManagement注解的Order屬性來指定 默認值為:Ordered.LOWEST_PRECEDENCE
                advisor.setOrder((Integer)this.enableTx.getNumber("order"));
            }
    
            return advisor;
        }
    
        @Bean
        @Role(2)
        // TransactionAttributeSource 這種類特別像 `TargetSource`這種類的設計模式
        public TransactionAttributeSource transactionAttributeSource() {
            return new AnnotationTransactionAttributeSource();
        }
    
        @Bean
        @Role(2)
      // 事務攔截器,它是個`MethodInterceptor`,它也是Spring處理事務最為核心的部分
    	// 請注意:你可以自己定義一個TransactionInterceptor(同名的),來覆蓋此Bean
        public TransactionInterceptor transactionInterceptor() {
            TransactionInterceptor interceptor = new TransactionInterceptor();
            interceptor.setTransactionAttributeSource(this.transactionAttributeSource());
            if (this.txManager != null) {
                interceptor.setTransactionManager(this.txManager);
            }
            return interceptor;
        }
    }
    @Configuration
    public abstract class AbstractTransactionManagementConfiguration implements ImportAware {
        @Nullable
        protected AnnotationAttributes enableTx;
       
      // 此處:注解的默認的事務處理器(可議通過實現(xiàn)接口TransactionManagementConfigurer來自定義配置)
    	// 因為事務管理器這個東西,一般來說全局一個就行,但是Spring也提供了定制化的能力~~~
    	  @Nullable
        protected PlatformTransactionManager txManager;
    
        public AbstractTransactionManagementConfiguration() {
        }
    
        public void setImportMetadata(AnnotationMetadata importMetadata) {
            this.enableTx = AnnotationAttributes.fromMap(importMetadata.getAnnotationAttributes(EnableTransactionManagement.class.getName(), false));
          //這個注解@EnableTransactionManagement是必須的~~~~~~~~~~~~~~~~否則報錯了
            if (this.enableTx == null) {
                throw new IllegalArgumentException("@EnableTransactionManagement is not present on importing class " + importMetadata.getClassName());
            }
        }
    
        @Autowired(
            required = false
        )
      // 這里和@Async的處理一樣,配置文件可以實現(xiàn)這個接口。然后給注解驅(qū)動的給一個默認的事務管理器~~~~
        void setConfigurers(Collection<TransactionManagementConfigurer> configurers) {
            if (!CollectionUtils.isEmpty(configurers)) {
              // 同樣的,最多也只允許你去配置一個~~~
                if (configurers.size() > 1) {
                    throw new IllegalStateException("Only one TransactionManagementConfigurer may exist");
                } else {
                    TransactionManagementConfigurer configurer = (TransactionManagementConfigurer)configurers.iterator().next();
                    this.txManager = configurer.annotationDrivenTransactionManager();
                }
            }
        }
    
        @Bean(
            name = {"org.springframework.transaction.config.internalTransactionalEventListenerFactory"}
        )
        @Role(2)
        public static TransactionalEventListenerFactory transactionalEventListenerFactory() {
            return new TransactionalEventListenerFactory();
        }
    }
BeanFactoryTransactionAttributeSourceAdvisor

Springboot中@Transactional的作用是什么

TransactionAttributeSourcePointcut

這個就是事務的匹配Pointcut切面,決定了哪些類需要生成代理對象從而應用事務。

    // 首先它的訪問權(quán)限事default 顯示是給內(nèi)部使用的
    // 首先它繼承自StaticMethodMatcherPointcut   所以`ClassFilter classFilter = ClassFilter.TRUE;` 匹配所有的類
    // 并且isRuntime=false  表示只需要對方法進行靜態(tài)匹配即可~~~~
    abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
    
    	// 方法的匹配  靜態(tài)匹配即可(因為事務無需要動態(tài)匹配這么細粒度~~~)
    	@Override
    	public boolean matches(Method method, Class<?> targetClass) {
    		// 實現(xiàn)了如下三個接口的子類,就不需要被代理了  直接放行
    		// TransactionalProxy它是SpringProxy的子類。  如果是被TransactionProxyFactoryBean生產(chǎn)出來的Bean,就會自動實現(xiàn)此接口,那么就不會被這里再次代理了
    		// PlatformTransactionManager:spring抽象的事務管理器~~~
    		// PersistenceExceptionTranslator對RuntimeException轉(zhuǎn)換成DataAccessException的轉(zhuǎn)換接口
    		if (TransactionalProxy.class.isAssignableFrom(targetClass) ||
    				PlatformTransactionManager.class.isAssignableFrom(targetClass) ||
    				PersistenceExceptionTranslator.class.isAssignableFrom(targetClass)) {
    			return false;
    		}
    		
    		// 重要:拿到事務屬性源~~~~~~
    		// 如果tas == null表示沒有配置事務屬性源,那是全部匹配的  也就是說所有的方法都匹配~~~~(這個處理還是比較讓我詫異的~~~)
    		// 或者 標注了@Transaction這樣的注解的方法才會給與匹配~~~
    		TransactionAttributeSource tas = getTransactionAttributeSource();
    		return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
    	}	
    	...
    	// 由子類提供給我,告訴事務屬性源~~~
    	@Nullable
    	protected abstract TransactionAttributeSource getTransactionAttributeSource();
    }
@Transactional

這個事務注解可以用在類上,也可以用在方法上。

  • 將事務注解標記到服務組件類級別,相當于為該服務組件的每個服務方法都應用了這個注解

  • 事務注解應用在方法級別,是更細粒度的一種事務注解方式

注意 : 如果某個方法和該方法所屬類上都有事務注解屬性,優(yōu)先使用方法上的事務注解屬性。

另外,Spring 支持三個不同的事務注解 :

  • Spring 事務注解 org.springframework.transaction.annotation.Transactional

  • JTA事務注解 ·javax.transaction.Transactional·

  • EJB 3 事務注解 ·javax.ejb.TransactionAttribute·

自定義TransactionManagementConfigurer
    @Configuration
    @EnableTransactionManagement
    public class MyTransactionManagementConfigurer implements TransactionManagementConfigurer {
        @Bean
        public PlatformTransactionManager transactionManager(DataSource dataSource) {
            DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(dataSource);
            return dataSourceTransactionManager;
        }
    
        @Override
        public PlatformTransactionManager annotationDrivenTransactionManager() {
            return null;
        }
    }
@EnableAspectJAutoProxy和@EnableTransactionManagement優(yōu)先級?
  • @EnableAspectJAutoProxy會像容器注入AnnotationAwareAspectJAutoProxyCreator

  • @EnableTransactionManagement會像容器注入InfrastructureAdvisorAutoProxyCreator

    public abstract class AopConfigUtils {
    	...
    	@Nullable
    	private static BeanDefinition registerOrEscalateApcAsRequired(
    			Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
    		
    		// 可以發(fā)現(xiàn)這里有一個很巧妙的處理:會對自動代理創(chuàng)建器進行升級~~~~
    		// 所以如果你第一次進來的是`InfrastructureAdvisorAutoProxyCreator`,第二次進來的是`AnnotationAwareAspectJAutoProxyCreator`,那就會取第二次進來的這個Class
    		// 反之則不行。這里面是維護的一個優(yōu)先級順序的,具體參看本類的static代碼塊,就是順序  最后一個`AnnotationAwareAspectJAutoProxyCreator`才是最為強大的
    		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;
    		}
    
    		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;
    	}
    	...
    }

上述就是小編為大家分享的Springboot中@Transactional的作用是什么了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI