Springboot源碼分析之@Transactional

摘要:

SpringBoot有多瞭解,其實就是看你對Spring Framework有多熟悉~ 好比SpringBoot大量的模塊裝配的設計模式,其實它屬於Spring Framework提供的能力。SpringBoot大行其道的今天,基於XML配置的Spring Framework的使用方式註定已成爲過去式。註解驅動應用,面向元數據編程已然成受到愈來愈多開發者的偏好了,畢竟它的便捷程度、優點都是XML方式不可比擬的。java

@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後續章節會分析

**提示:**使用@EnableTransactionManagement註解前,請務必保證你已經配置了至少一個PlatformTransactionManager的Bean,不然會報錯。(固然你也能夠實現TransactionManagementConfigurer來提供一個專屬的,只是咱們通常都不這麼去作~~~)spring

開啓註解驅動

@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目前所知的三個子類是:AsyncConfigurationSelectorTransactionManagementConfigurationSelectorCachingConfigurationSelector。因而可知後面還會着重分析的Spring的緩存體系@EnableCaching,模式也是和這個極其相似的~~~異步

AutoProxyRegistrar

它是個ImportBeanDefinitionRegistrar,能夠實現本身向容器裏註冊Bean的定義信息ide

// @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`這個屬性的值,所以也會產生關聯影響~
            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`,可是若出現屢次的話,這裏不是覆蓋的形式,而是以優先級的形式
                            AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                          //看要不要強制使用CGLIB的方式(由此能夠發現  這個屬性若出現屢次,是會是覆蓋的形式)
                            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的源碼你會發現,事務這塊向容器注入的是一個InfrastructureAdvisorAutoProxyCreator,而且看看是採用CGLIB仍是JDK代理。它主要是讀取Advisor類,並對符合的bean進行二次代理。ui

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;
       
      // 此處:註解的默認的事務處理器(可議經過實現接口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的處理同樣,配置文件能夠實現這個接口。而後給註解驅動的給一個默認的事務管理器~~~~
        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

file

TransactionAttributeSourcePointcut

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

// 首先它的訪問權限事default 顯示是給內部使用的
    // 首先它繼承自StaticMethodMatcherPointcut   因此`ClassFilter classFilter = ClassFilter.TRUE;` 匹配全部的類
    // 而且isRuntime=false  表示只須要對方法進行靜態匹配便可~~~~
    abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
    
    	// 方法的匹配  靜態匹配便可(由於事務無須要動態匹配這麼細粒度~~~)
    	@Override
    	public boolean matches(Method method, Class<?> targetClass) {
    		// 實現了以下三個接口的子類,就不須要被代理了  直接放行
    		// TransactionalProxy它是SpringProxy的子類。  若是是被TransactionProxyFactoryBean生產出來的Bean,就會自動實現此接口,那麼就不會被這裏再次代理了
    		// 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();
    }

@Transactional

這個事務註解能夠用在類上,也能夠用在方法上。.net

  • 將事務註解標記到服務組件類級別,至關於爲該服務組件的每一個服務方法都應用了這個註解
  • 事務註解應用在方法級別,是更細粒度的一種事務註解方式

注意 : 若是某個方法和該方法所屬類上都有事務註解屬性,優先使用方法上的事務註解屬性。

另外,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優先級?

  • @EnableAspectJAutoProxy會像容器注入AnnotationAwareAspectJAutoProxyCreator
  • @EnableTransactionManagement會像容器注入InfrastructureAdvisorAutoProxyCreator
public abstract class AopConfigUtils {
    	...
    	@Nullable
    	private static BeanDefinition registerOrEscalateApcAsRequired(
    			Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
    		
    		// 能夠發現這裏有一個很巧妙的處理:會對自動代理建立器進行升級~~~~
    		// 因此若是你第一次進來的是`InfrastructureAdvisorAutoProxyCreator`,第二次進來的是`AnnotationAwareAspectJAutoProxyCreator`,那就會取第二次進來的這個Class
    		// 反之則不行。這裏面是維護的一個優先級順序的,具體參看本類的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;
    	}
    	...
    }

從上面的分析能夠知道:不管你的這些註解有多少個,不管他們的前後順序如何,它內部都有咯優先級提高的機制來保證向下的覆蓋兼容。所以通常狀況下,咱們使用的都是最高級的AnnotationAwareAspectJAutoProxyCreator這個自動代理建立器~~~

相關文章
相關標籤/搜索