這期內容當中小編將會給大家?guī)碛嘘PSpringboot中@Transactional的作用是什么,文章內容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
創(chuàng)新互聯(lián)公司提供網(wǎng)站設計制作、網(wǎng)站建設、網(wǎng)頁設計,品牌網(wǎng)站制作,一元廣告等致力于企業(yè)網(wǎng)站建設與公司網(wǎng)站制作,十余年的網(wǎng)站開發(fā)和建站經(jīng)驗,助力企業(yè)信息化建設,成功案例突破上千,是您實現(xiàn)網(wǎng)站建設的好選擇.
對SpringBoot
有多了解,其實就是看你對Spring Framework
有多熟悉~ 比如SpringBoot
大量的模塊裝配的設計模式,其實它屬于Spring Framework提供的能力。SpringBoot大行其道的今天,基于XML
配置的Spring Framework的使用方式注定已成為過去式。注解驅動應用,面向元數(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> 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); } } }
**提示:**使用@EnableTransactionManagement
注解前,請務必保證你已經(jīng)配置了至少一個PlatformTransactionManager
的Bean,否則會報錯。(當然你也可以實現(xiàn)TransactionManagementConfigurer
來提供一個專屬的,只是我們一般都不這么去做~~~)
@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; }
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector{ 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
,模式也是和這個極其類似的~~~
它是個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)影響~ SetannTypes = 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進行二次代理。
@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)這個接口。然后給注解驅動的給一個默認的事務管理器~~~~ void setConfigurers(Collectionconfigurers) { 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(); } }
這個就是事務的匹配Pointcut
切面,決定了哪些類需要生成代理對象從而應用事務。
// 首先它的訪問權限事default 顯示是給內部使用的 // 首先它繼承自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轉換成DataAccessException的轉換接口 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(); }
這個事務注解可以用在類上,也可以用在方法上。
將事務注解標記到服務組件類級別,相當于為該服務組件的每個服務方法都應用了這個注解
事務注解應用在方法級別,是更細粒度的一種事務注解方式
注意 : 如果某個方法和該方法所屬類上都有事務注解屬性,優(yōu)先使用方法上的事務注解屬性。
另外,Spring 支持三個不同的事務注解 :
Spring事務注解 org.springframework.transaction.annotation.Transactional
JTA事務注解 ·javax.transaction.Transactional·
EJB 3事務注解 ·javax.ejb.TransactionAttribute·
@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
會像容器注入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的作用是什么了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注創(chuàng)新互聯(lián)行業(yè)資訊頻道。