Spring原始碼深度解析之事務
Spring原始碼深度解析之事務
目錄
一、JDBC方式下的事務使用示例
(1)建立資料表結構
(2)建立對應資料表的PO
(3)建立表和實體之間的對映
(4)建立資料操作介面
(5)建立資料操作介面實現類
(6)建立Spring配置檔案
(7)測試
二、事務自定義標籤
(一)註冊InfrastructureAdvisorAutoProxyCreator
(二)獲取對應class/method的增強器
(1)尋找候選增強器
(2)候選增強器中尋找到匹配項
三、事務增強器
(一)建立事務
(1)獲取事務
(2)處理已經存在的事務
(3)準備事務資訊
(二)回滾處理
(1)回滾條件
(2)回滾處理
(3)回滾後的資訊清除
(三)事務提交
Spring宣告式事務讓我們從複雜的事務處理中得到解脫,使我們再也不需要去處理獲得連線、關閉連線、事務提交和回滾等操作。再也不需要在與事務相關的方法中處理大量的try…catch…finally程式碼。Spring中事務的使用雖然已經相對簡單得多,但是,還是有很多的使用及配置規劃,有興趣的讀者可以自己查閱相關資料進行深入的研究,這裡只列舉出最常用的使用方法。
同樣,我們還是以最簡單的示例來進行直觀的介紹。
一、JDBC方式下事務使用示例
(1)建立資料表結構
1 CREATE TABLE 'user'( 2 'id' int(11) NOT NULL auto_increment, 3 'name' varchar(255) default null, 4 'age' int(11) default null, 5 'sex' varchar(255) default null, 6 PRIMARY KEY ('id') 7 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
(2)建立對應資料表的PO
1 public class User { 2 private int id; 3 private String name; 4 private int age; 5 private String sex; 6 //省略set/get方法 7 }
(3)建立表和實體之間的對映
1 public class UserRowMapper implements RowMapper { 2 @Override 3 public Object mapRow(ResultSet set, int index) throws SQLException { 4 User person = new User(set.getInt('id'), set.getString("name"), set.getInt("age"), set.getString("sex")); 5 return person; 6 } 7 }
(4)建立資料操作介面
1 @Transactional(propagation-Propagation.REQUIRED) 2 public interface UserService { 3 public void save(User user) throws Exception; 4 }
(5)建立資料操作介面實現類
1 public class UserServiceImpl implements UserService { 2 private JdbcTemplate jdbcTemplate; 3 4 //設定資料來源 5 public void setDataSource(DataSource dataSource) { 6 this.jdbcTemplate = new JdbcTemplate(dataSource); 7 } 8 9 public void save(User user) throws Exception { 10 jdbcTemplate.update("insert into user(name, age, sex) value(?, ?, ?)", 11 new Object[] {user.getName(), usr.getAge(), user.getSex()}, 12 new int[] {java.sql.Types.VARCHAR, java.sql.Type.INTEGER, java.sql.Types.VARCHAR}); 13 14 //事務測試,加上這句程式碼則資料不會儲存到資料庫中 15 throw new RuntimeException("aa"); 16 } 17 18 }
(6)建立Spring配置檔案
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://w3.org/2001/XMLSchema-instance" 4 xmlns:tx="http://www.springframework.org/schema/tx" 5 xmlns:context="http://www.springframework.org/schema/context" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 8 http://www.springframework.org/schema/context 9 http://www.springframework.org/schema/context/spring-context-2.5.xsd 10 http://www.springframework.org/schema/tx 11 http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 12 13 <tx:annotation-driven transaction-manager="transactionManager"/> 14 15 <bean id="transactionManager" class="org.springframe.jdbc.datasource.DataSourceTransactionManager"> 16 <property name="dataSource" ref="dataSource"/> 17 </bean> 18 19 //配置資料來源 20 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 21 <property name="driverClassName" value="com.mysql.jdbc.Driver"/> 22 <property name="uri" value="jdbc:mysql://localhost:3306/lexueba"/> 23 <property name="username" value="root"/> 24 <property name="password" value="haojia0421xixi"/> 25 <!--連線池啟動時的初始值--> 26 <property name="initialSize" value="1"/> 27 <!--連線池的最大值--> 28 <property name="maxActive" value="300"/> 29 <!--最大空閒值,當經過一個高峰時間後,連線池可以慢慢將已經用不到的連線慢慢釋放一部分,一直減少到maxIdle為止--> 30 <property name="maxIdle" value="2"/> 31 <!--最小空閒值,當空閒的連線數少於閥值時,連線池就會預申請去一些連線,以免洪峰來時來不及申請--> 32 <property name="minIdle" value="1"/> 33 </bean> 34 35 <!--配置業務 bean:PersonServiceBean --> 36 <bean id="userService" class="service.UserServiceImple"> 37 <!--向屬性dataSource注入資料來源--> 38 <property name="dataSource" ref="dataSource"></property> 39 </bean> 40 41 </beans>
(7)測試
1 public static void main(String[] args) throws Exception { 2 ApplicationContext act = new ClassPathXmlApplicationContext("bean.xml"); 3 4 UserService userService = (UserService) act.getBean("userService"); 5 User user = new User(); 6 user.setName("張三CCC"); 7 user.setAge(20); 8 user.setSex("男"); 9 //儲存一條記錄 10 userService.save(user); 11 }
上面測測試示例中,UserServiceImpl類對介面UserService中的save函式的實現最後加入了一句丟擲異常的程式碼:throw new RuntimeException(“aa”)。當註釋掉這段程式碼執行測試類,那麼會看到資料被成功的儲存到了資料庫中,但是如果加入這段程式碼再次執行測試類,發現此處的操作並不會將資料儲存到資料庫中。
注意:預設情況下,Spring中的事務處理只對RuntimeException方法進行回滾,所以,如果此處將RuntimeException替換成普通的Exception不會產生回滾效果。
二、事務自定義標籤
對於Spring中事務功能的程式碼分析。我們首先從配置檔案開始入手,在配置檔案中有這樣一個配置<tx:annotation-driven/>。可以說此處配置是事務的開關,如果沒有此處的配置,那麼Spring中將不存在事務的功能。那麼我們就從這個配置開始分析。
根據之前的分析。我們因此可以判斷,在自定義標籤中的解析過程中一定是做了一些輔助性的操作,於是我們先從自定義的標籤入手進行分析。
對於關鍵字annotation-driven,在TxNamespaceHandler類(package org.springframework.transaction.config)中的init()方法中進行了處理:
1 public void init() { 2 registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser()); 3 registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser()); 4 registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser()); 5 }
根據自定義標籤的使用規則及上面的程式碼,可以知道,在遇到諸如<tx:annotation-driven為開頭的配置後,Spring都會使用AnnotationDrivenBeanDefinitionParser類(package org.springframework.transaction.config)的parse()方法進行解析。
1 public BeanDefinition parse(Element element, ParserContext parserContext) { 2 registerTransactionalEventListenerFactory(parserContext); 3 String mode = element.getAttribute("mode"); 4 if ("aspectj".equals(mode)) { 5 // mode="aspectj" 6 registerTransactionAspect(element, parserContext); 7 if (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader())) { 8 registerJtaTransactionAspect(element, parserContext); 9 } 10 } 11 else { 12 // mode="proxy" 13 AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext); 14 } 15 return null; 16 }
在解析中存在對於mode屬性的判斷,根據程式碼,如果我們需要使用AspectJ的方式進行事務切入(Spring中的事務是以AOP為基礎的),那麼可以使用這樣的配置:
<tx:annotation-driven transaction-manager="transactionManager"/ mode="aspectJ">
(一)註冊InfrastructureAdvisorAutoProxyCreator
我們以預設配置為例子進行分析,進入AopAutoProxyConfigurer類(AnnotationDrivenBeanDefinitionParser類的內部類)的configureAutoProxyCreator函式:
1 public static void configureAutoProxyCreator(Element element, ParserContext parserContext) { 2 AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element); 3 4 String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME; 5 if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) { 6 Object eleSource = parserContext.extractSource(element); 7 8 // Create the TransactionAttributeSource definition. 9 //建立TransactionAttributeSource的bean 10 RootBeanDefinition sourceDef = new RootBeanDefinition( 11 "org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"); 12 sourceDef.setSource(eleSource); 13 sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); 14 //註冊bean,並使用Spring中的定義規則生成beanname 15 String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef); 16 17 // Create the TransactionInterceptor definition. 18 //建立TransactionInterceptor的bean 19 RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class); 20 interceptorDef.setSource(eleSource); 21 interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); 22 registerTransactionManager(element, interceptorDef); 23 interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName)); 24 String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef); 25 26 // Create the TransactionAttributeSourceAdvisor definition. 27 //建立TransactionAttributeSourceAdvisor的bean 28 RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class); 29 advisorDef.setSource(eleSource); 30 advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); 31 //將sourceName的bean注入advisorDef的transactionAttributeSource屬性中 32 advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName)); 33 //將interceptorName的bean注入advisorDef的adviceBeanName屬性中 34 advisorDef.getPropertyValues().add("adviceBeanName", interceptorName); 35 //如果配置了order屬性,則加入到bean中 36 if (element.hasAttribute("order")) { 37 advisorDef.getPropertyValues().add("order", element.getAttribute("order")); 38 } 39 parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef); 40 41 //建立CompositeComponentDefinition 42 CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource); 43 compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName)); 44 compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName)); 45 compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName)); 46 parserContext.registerComponent(compositeDef); 47 } 48 }
上面的程式碼註冊了代理類及三個bean,很多讀者會直接略過,認為只是註冊三個bean而已,確實,這裡只註冊量三個bean,但是這三個bean支撐了整個事務的功能,那麼這三個bean是怎麼組織起來的呢?
首先,其中的兩個bean被註冊到了一個名為advisorDef的bean中,advisorDef使用BeanFactoryTransactionAttributeSourceAdvisor作為其class屬性。也就是說BeanFactoryTransactionAttributeSourceAdvisor代表著當前bean,具體程式碼如下:
advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
那麼如此組裝的目的是什麼呢?先留下一個懸念,接著分析程式碼。上面configureAutoProxyCreator函式中的第一句貌似很簡單但卻是很重要的程式碼:
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
進入這個函式,AopNamespaceUtils類(package org.springframework.aop.config)的registerAutoProxyCreatorIfNecessary函式:
1 public static void registerAutoProxyCreatorIfNecessary( 2 ParserContext parserContext, Element sourceElement) { 3 4 BeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary( 5 parserContext.getRegistry(), parserContext.extractSource(sourceElement)); 6 useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement); 7 registerComponentIfNecessary(beanDefinition, parserContext); 8 }
上面函式又呼叫了AopConfigUtils類(package org.springframework.aop.config)的registerAutoProxyCreatorIfNecessary函式:
1 public static BeanDefinition registerAutoProxyCreatorIfNecessary( 2 BeanDefinitionRegistry registry, @Nullable Object source) { 3 4 return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source); 5 }
對於解析來的額程式碼流程AOP中已經有所分析,上面兩個函式主要的目的是註冊InfrastructureAdvisorAutoProxyCreator型別(package org.springframework.aop.framework.autoproxy)的bean,那麼註冊這個類的目的是什麼呢?
檢視該類的層次結構,可以看到InfrastructureAdvisorAutoProxyCreator繼承自AbstractAdvisorAutoProxyCreator繼承自AbstractAutoProxyCreator繼承自SmartInstantiationAwareBeanPostProcessor繼承自InstantiationAwareBeanPostProcessor(含postProcessAfterInitialization方法),也就是說在Spring中,所有bean例項化時Spring都會保證呼叫其postProcessAfterInitialization方法。其實現是在父類AbstractAutoProxyCreator類中實現。
以之前的示例為例,當例項化userService的bean時便會呼叫此方法,AbstractAutoProxyCreator類(packageorg.springframework.aop.framework.autoproxy)的postProcessAfterInitialization方法:
1 public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { 2 if (bean != null) { 3 //根據給定的bean的class和name構建出key,格式:beanClassName_beanName 4 Object cacheKey = getCacheKey(bean.getClass(), beanName); 5 if (this.earlyProxyReferences.remove(cacheKey) != bean) { 6 //一個非常核心的方法:wrapIfNecessary(),如果它適合被代理,則需要封裝指定的bean。 7 return wrapIfNecessary(bean, beanName, cacheKey); 8 } 9 } 10 return bean; 11 }
這裡實現的主要目的是對指定的bean進行封裝,當然首先要確定是否需要封裝,檢測以及封裝的的工作都委託給了wrapIfNecessary函式進行,AbstractAutoProxyCreator類的wrapIfNecessary方法:
1 protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { 2 //如果已經處理過 3 if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { 4 return bean; 5 } 6 //這個bean無需增強 7 if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { 8 return bean; 9 } 10 //判斷給定的bean是否是一個基礎設施類,基礎設施類不應代理,或者配置了指定bean不需要代理。 11 //所謂InfrastructureClass就是指Advice/PointCut/Advisor等介面的實現類。 12 if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { 13 this.advisedBeans.put(cacheKey, Boolean.FALSE); 14 return bean; 15 } 16 17 // 如果存在增強方法則建立代理 18 //獲取這個bean的advice 19 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); 20 //如果獲取到了增強則需要針對增強建立代理 21 if (specificInterceptors != DO_NOT_PROXY) { 22 this.advisedBeans.put(cacheKey, Boolean.TRUE); 23 //建立代理 24 Object proxy = createProxy( 25 bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); 26 this.proxyTypes.put(cacheKey, proxy.getClass()); 27 return proxy; 28 } 29 30 this.advisedBeans.put(cacheKey, Boolean.FALSE); 31 return bean; 32 }
WrapIfNecessary函式功能實現起來很複雜,但是邏輯上理解起來還是相對簡單的,在wrapIfNecessary函式中主要的工作如下:
①找出指定bean對應的增強器。
②根據找出的增強器建立代理。
聽起來似乎簡單的邏輯,Spring中又做了哪些複雜的工作呢?對於建立代理的部分,通過之前的分析大家已經很熟悉了,但是對於增強器的獲取,Spring又是怎麼做的呢?
(二)獲取對應的class/method的增強器
獲取指定bean對應的增強器,其中包含兩個關鍵字:增強器和對應。也就是說在getAdvicesAndAdvisorsForBean函式中,不但要找出增強器,而且還需要判斷增強器是否滿足要求。AbstractAutoProxyCreator類的wrapIfNecessary方法中呼叫了getAdvicesAndAdvisorsForBean,AbstractAutoProxyCreator類只對該方法進行定義,真正實現在其子類AbstractAdvisorAutoProxyCreator(package org.springframework.aop.framework.autoproxy)中:
1 protected Object[] getAdvicesAndAdvisorsForBean( 2 Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) { 3 4 List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); 5 if (advisors.isEmpty()) { 6 return DO_NOT_PROXY; 7 } 8 return advisors.toArray(); 9 }
上述函式呼叫了該類中的findEligibleAdvisors函式:
1 protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { 2 List<Advisor> candidateAdvisors = findCandidateAdvisors(); 3 List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); 4 extendAdvisors(eligibleAdvisors); 5 if (!eligibleAdvisors.isEmpty()) { 6 eligibleAdvisors = sortAdvisors(eligibleAdvisors); 7 } 8 return eligibleAdvisors; 9 }
其實我們也漸漸地體會到Spring中程式碼的優秀,即使是一個很複雜的邏輯,在Spring中也會被拆分為若干個小的邏輯,然後在每個函式中實現,使得每個函式的邏輯簡單到我們能快速的理解,而不會像有些人開發的那樣,將一大堆的邏輯都羅列在一個函式中,給後期維護文員造成巨大的困擾。
同樣,通過上面的函式,Spring又將任務進行了拆分,分成了獲取所有增強器與增強器是否匹配兩個功能點。
(1)尋找候選增強器
在findCandidateAdvisors函式中完成的就是獲取增強器的功能,AbstractAdvisorAutoProxyCreator類的findCandidateAdvisors函式:
1 protected List<Advisor> findCandidateAdvisors() { 2 Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available"); 3 return this.advisorRetrievalHelper.findAdvisorBeans(); 4 }
上面函式呼叫了advisorRetrievalHelper類(package org.springframework.aop.framework.autoproxy)的findAdvisorBeans函式,進入函式:
1 public List<Advisor> findAdvisorBeans() { 2 //cachedAdvisorBeanNames是advisor名稱的快取 3 String[] advisorNames = this.cachedAdvisorBeanNames; 4 //如果cachedAdvisorBeanNames為空,則到容器中查詢,並設定快取,後續直接使用快取即可 5 if (advisorNames == null) { 6 // Do not initialize FactoryBeans here: We need to leave all regular beans 7 // uninitialized to let the auto-proxy creator apply to them! 8 //從容器中查詢Advisor型別的bean的名稱 9 advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( 10 this.beanFactory, Advisor.class, true, false); 11 this.cachedAdvisorBeanNames = advisorNames; 12 } 13 if (advisorNames.length == 0) { 14 return new ArrayList<>(); 15 } 16 17 List<Advisor> advisors = new ArrayList<>(); 18 //遍歷advisorNames 19 for (String name : advisorNames) { 20 if (isEligibleBean(name)) { 21 //忽略鄭州建立中的advisor bean 22 if (this.beanFactory.isCurrentlyInCreation(name)) { 23 if (logger.isTraceEnabled()) { 24 logger.trace("Skipping currently created advisor '" + name + "'"); 25 } 26 } 27 else { 28 try { 29 //呼叫getBean方法從容器中獲取名稱為name的bean,並將bean新增到advisors中 30 advisors.add(this.beanFactory.getBean(name, Advisor.class)); 31 } 32 catch (BeanCreationException ex) { 33 Throwable rootCause = ex.getMostSpecificCause(); 34 if (rootCause instanceof BeanCurrentlyInCreationException) { 35 BeanCreationException bce = (BeanCreationException) rootCause; 36 String bceBeanName = bce.getBeanName(); 37 if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) { 38 if (logger.isTraceEnabled()) { 39 logger.trace("Skipping advisor '" + name + 40 "' with dependency on currently created bean: " + ex.getMessage()); 41 } 42 // Ignore: indicates a reference back to the bean we're trying to advise. 43 // We want to find advisors other than the currently created bean itself. 44 continue; 45 } 46 } 47 throw ex; 48 } 49 } 50 } 51 } 52 return advisors; 53 }
對於上面的函式,你看懂其中的奧祕了嗎?首先是通過BeanFactoryUtils類提供的工具方法獲取所有對應的Advisor.class的類。
1 //從容器中查詢Advisor型別的bean的名稱 2 advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( 3 this.beanFactory, Advisor.class, true, false);
進入BeanFactoryUtils類(package org.springframework.beans.factory)的beanNamesForTypeIncludingAncestors函式:
1 public static String[] beanNamesForTypeIncludingAncestors( 2 ListableBeanFactory lbf, ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) { 3 4 Assert.notNull(lbf, "ListableBeanFactory must not be null"); 5 String[] result = lbf.getBeanNamesForType(type, includeNonSingletons, allowEagerInit); 6 if (lbf instanceof HierarchicalBeanFactory) { 7 HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf; 8 if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) { 9 String[] parentResult = beanNamesForTypeIncludingAncestors( 10 (ListableBeanFactory) hbf.getParentBeanFactory(), type, includeNonSingletons, allowEagerInit); 11 result = mergeNamesWithParent(result, parentResult, hbf); 12 } 13 } 14 return result; 15 }
從上面程式碼可以看出,實際呼叫的是ListableBeanFactory類提供的getBeanNamesForType函式。
而當我們知道增強器在容器中beanName時,獲取增強器已經不是問題了,在BeanFactory中提供了這樣的方法,可以幫助我們快速的定位對應的bean例項。
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
或許你已經忘了之前留下的懸念,在我們講解自定義標籤時曾經註冊了一個型別為BeanFactoryTransactionAttributeSourceAdvisor的bean,(package org.springframework.transaction.config 包中的AnnotationDrivenBeanDefinitionParser類的內部類AopAutoProxyConfigurer類中),而在此bean總我們又注入另外兩個Bean,那麼此時這個Bean就會被開始使用了。因為BeanFactoryTransactionAttributeSourceAdvisor同樣也實現了Advisor介面,那麼在獲取所有增強器是自然也會將此bean提取出來並隨著其他增強器一起在 後續的步驟中被織入代理。
(2)候選增強器中尋找到匹配項
當找出對應的增強後,接下來的任務就是看這些增強是否與對應的class匹配了,當然不只是class,class內部的方法如果匹配也可以通過驗證,AbstractAdvisorAutoProxyCreator類(packageorg.springframework.aop.framework.autoproxy)的findAdvisorsThatCanApply函式:
1 protected List<Advisor> findAdvisorsThatCanApply( 2 List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) { 3 4 ProxyCreationContext.setCurrentProxiedBeanName(beanName); 5 try { 6 return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); 7 } 8 finally { 9 ProxyCreationContext.setCurrentProxiedBeanName(null); 10 } 11 }
其中又呼叫了AopUtils類(package org.springframework.aop.support)的findAdvisorsThatCanApply函式:
1 public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) { 2 if (candidateAdvisors.isEmpty()) { 3 return candidateAdvisors; 4 } 5 List<Advisor> eligibleAdvisors = new ArrayList<>(); 6 for (Advisor candidate : candidateAdvisors) { 7 //刷選IntroductionAdvisor引介型別的通知器 8 if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) { 9 eligibleAdvisors.add(candidate); 10 } 11 } 12 boolean hasIntroductions = !eligibleAdvisors.isEmpty(); 13 for (Advisor candidate : candidateAdvisors) { 14 if (candidate instanceof IntroductionAdvisor) { 15 //引介增強已經處理 16 continue; 17 } 18 //刷選普通型別的通知器 19 if (canApply(candidate, clazz, hasIntroductions)) { 20 eligibleAdvisors.add(candidate); 21 } 22 } 23 return eligibleAdvisors; 24 }
上面函式呼叫了該類中的canApply函式:
1 public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) { 2 if (advisor instanceof IntroductionAdvisor) { 3 /* 4 * 從通知器中獲取型別過濾器 ClassFilter,並呼叫 matchers 方法進行匹配。 5 * ClassFilter 介面的實現類 AspectJExpressionPointcut 為例,該類的 6 * 匹配工作由 AspectJ 表示式解析器負責,具體匹配細節這個就沒法分析了,我 7 * AspectJ 表示式的工作流程不是很熟 8 */ 9 return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass); 10 } 11 else if (advisor instanceof PointcutAdvisor) { 12 PointcutAdvisor pca = (PointcutAdvisor) advisor; 13 // 對於普通型別的通知器,這裡繼續呼叫過載方法進行篩選 14 return canApply(pca.getPointcut(), targetClass, hasIntroductions); 15 } 16 else { 17 // It doesn't have a pointcut so we assume it applies. 18 return true; 19 } 20 }
當前我們分析的是對於UserService是否適用於此增強方法,那麼當前的advisor就是之前查找出來的型別為BeanFactoryTransactionAttributeSourceAdvisor的bean例項,而通過類的層次幾個我們又知道:BeanFactoryTransactionAttributeSourceAdvisor間接實現了PointAdvisor(BeanFactoryTransactionAttributeSourceAdvisor繼承自AbstractBeanFactoryPointcutAdvisor繼承自AbstractPointcutAdvisor繼承自PointcutAdvisor)。因此,在canApply函式中的第二個if判斷時就會通過判斷,會將BeanFactoryTransactionAttributeSourceAdvisor中的getPointcut()方法返回值作為引數繼續呼叫canApply方法,而getPointcut ()方法返回的是TransactionAttributeSourcePointcut型別的例項。對於transactionAttributeSource這個屬性大家還有印象嗎?這是在解析自定義標籤時注入進去的。BeanFactoryTransactionAttributeSourceAdvisor類中程式碼:
1 private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() { 2 @Override 3 @Nullable 4 protected TransactionAttributeSource getTransactionAttributeSource() { 5 return transactionAttributeSource; 6 } 7 };
那麼使用TransactionAttributeSourcePointcut型別的例項作為函式引數繼續跟蹤canApply,AopUtils類(package org.springframework.aop.support)的CanApply函式:
1 public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) { 2 Assert.notNull(pc, "Pointcut must not be null"); 3 //使用 ClassFilter 匹配 class 4 if (!pc.getClassFilter().matches(targetClass)) { 5 return false; 6 } 7 8 MethodMatcher methodMatcher = pc.getMethodMatcher(); 9 if (methodMatcher == MethodMatcher.TRUE) { 10 // No need to iterate the methods if we're matching any method anyway... 11 return true; 12 } 13 14 IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null; 15 if (methodMatcher instanceof IntroductionAwareMethodMatcher) { 16 introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher; 17 } 18 19 20 /* 21 * 查詢當前類及其父類(以及父類的父類等等)所實現的介面,由於介面中的方法是 public, 22 * 所以當前類可以繼承其父類,和父類的父類中所有的介面方法 23 */ 24 Set<Class<?>> classes = new LinkedHashSet<>(); 25 if (!Proxy.isProxyClass(targetClass)) { 26 classes.add(ClassUtils.getUserClass(targetClass)); 27 } 28 classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass)); 29 30 for (Class<?> clazz : classes) { 31 // 獲取當前類的方法列表,包括從父類中繼承的方法 32 Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz); 33 for (Method method : methods) { 34 // 使用 methodMatcher 匹配方法,匹配成功即可立即返回 35 if (introductionAwareMethodMatcher != null ? 36 introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) : 37 methodMatcher.matches(method, targetClass)) { 38 return true; 39 } 40 } 41 } 42 43 return false; 44 }
通過上面函式大致可以理清大體脈絡,首先獲取對應類的所有介面並連同類本身一起遍歷,遍歷過程中又對類中的方法再次遍歷,一旦匹配成功便認為這個類適用於當前的增強器。
到這裡我們不禁會有疑問,對於事務的配置不僅僅侷限於在函式上配置,我們都知道,在類或介面上的配置可以延續到類中的每個函式。那麼,如果針對每個函式進行檢測,在類本身上配置的事務屬性豈不是檢測不到了嗎?帶著這個疑問,我們繼續探求matcher方法。
做匹配的時候methodMatcher.matches(method, targetClass)會使用TransactionAttributeSourcePointcut類(package org.springframework.transaction.interceptor)的matches方法。
1 public boolean matches(Method method, Class<?> targetClass) { 2 //自定義標籤解析時注入 3 TransactionAttributeSource tas = getTransactionAttributeSource(); 4 return (tas == null || tas.getTransactionAttribute(method, targetClass) != null); 5 }
此時的tas表示AnnotationTransactionAttributeSource型別,而AnnotationTransactionAttributeSource型別的getTransactionAttribute方法如下(該方法在其父類AbstractFallbackTransactionAttributeSource中)。AbstractFallbackTransactionAttributeSource類(package org.springframework.transaction.interceptor)的getTransactionAttribute方法
1 public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) { 2 if (method.getDeclaringClass() == Object.class) { 3 return null; 4 } 5 6 // First, see if we have a cached value. 7 Object cacheKey = getCacheKey(method, targetClass); 8 TransactionAttribute cached = this.attributeCache.get(cacheKey); 9 if (cached != null) { 10 // Value will either be canonical value indicating there is no transaction attribute, 11 // or an actual transaction attribute. 12 if (cached == NULL_TRANSACTION_ATTRIBUTE) { 13 return null; 14 } 15 else { 16 return cached; 17 } 18 } 19 else { 20 // We need to work it out. 21 TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass); 22 // Put it in the cache. 23 if (txAttr == null) { 24 this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE); 25 } 26 else { 27 String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass); 28 if (txAttr instanceof DefaultTransactionAttribute) { 29 ((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification); 30 } 31 if (logger.isTraceEnabled()) { 32 logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr); 33 } 34 this.attributeCache.put(cacheKey, txAttr); 35 } 36 return txAttr; 37 } 38 }
很遺憾,在getTransactionAttribute函式中並沒有找到我們想要的程式碼,這裡是指常規的一貫的套路。嘗試從快取載入,如果對應資訊沒有被快取的話,工作又委託給了computeTransactionAttribute函式,在computeTransactionAttribute函式中我們看到了事務標籤的提取過程。AbstractFallbackTransactionAttributeSource類的computeTransactionAttribute方法:
1 protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) { 2 // Don't allow no-public methods as required. 3 if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) { 4 return null; 5 } 6 7 // The method may be on an interface, but we need attributes from the target class. 8 // If the target class is null, the method will be unchanged. 9 //method代表介面中的方法,specificMethod代表類中的方法 10 Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass); 11 12 // First try is the method in the target class. 13 //檢視方法中是否存在事務宣告 14 TransactionAttribute txAttr = findTransactionAttribute(specificMethod); 15 if (txAttr != null) { 16 return txAttr; 17 } 18 19 // Second try is the transaction attribute on the target class. 20 //檢視方法所在的類是否存在事務宣告 21 txAttr = findTransactionAttribute(specificMethod.getDeclaringClass()); 22 if (txAttr != null && ClassUtils.isUserLevelMethod(method)) { 23 return txAttr; 24 } 25 26 //如果存在介面,則到介面中去尋找 27 if (specificMethod != method) { 28 // Fallback is to look at the original method. 29 //查詢介面方法 30 txAttr = findTransactionAttribute(method); 31 if (txAttr != null) { 32 return txAttr; 33 } 34 // Last fallback is the class of the original method. 35 //到介面的類中去尋找 36 txAttr = findTransactionAttribute(method.getDeclaringClass()); 37 if (txAttr != null && ClassUtils.isUserLevelMethod(method)) { 38 return txAttr; 39 } 40 } 41 42 return null; 43 }
對於事物屬性的獲取規則相信大家已經很清楚,如果方法中存在事務屬性,則使用方法上的屬性,否則使用方法所在的類上的屬性,如果方法所在類的屬性上還是沒有搜尋到對應的事務屬性,那麼再搜尋介面中的方法,再沒有的話,最後嘗試搜尋介面的類上面的宣告。對於函式computeTransactionAttribute中的邏輯與我們所認識的規則並無差別,但是上面函式中並沒有真正的去做搜尋事務屬性的邏輯,而是搭建了一個執行框架,將搜尋事務屬性的任務委託給了findTransactionAttribute方法去執行。AnnotationTransactionAttributeSource類(package org.springframework.transaction.annotation)的findTransactionAttribute方法:
1 protected TransactionAttribute findTransactionAttribute(Method method) { 2 return determineTransactionAttribute(method); 3 }
上面函式呼叫了本類中的determineTransactionAttribute方法:
1 protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) { 2 for (TransactionAnnotationParser parser : this.annotationParsers) { 3 TransactionAttribute attr = parser.parseTransactionAnnotation(element); 4 if (attr != null) { 5 return attr; 6 } 7 } 8 return null; 9 }
this.annotationParsers是在當前類AnnotationTransactionAttributeSource初始化的時候初始化的,其中的值被加入了SpringTransactionAnnotationParser,也就是當進行屬性獲取的時候其實是使用SpringTransactionAnnotationParser類(package org.springframework.transaction.annotation)的parseTransactionAnnotation方法進行解析的:
1 public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) { 2 AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes( 3 element, Transactional.class, false, false); 4 if (attributes != null) { 5 return parseTransactionAnnotation(attributes); 6 } 7 else { 8 return null; 9 } 10 }
至此,我們終於看到了想看到的獲取註解標記的程式碼。首先會判斷當前的類是否含有Transactional註解,這是事務屬性的基礎,當然如果有的話會繼續呼叫SpringTransactionAnnotationParser類的parseTransactionAnnotation方法解析詳細的屬性:
1 protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) { 2 RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); 3 4 //解析propagation 5 Propagation propagation = attributes.getEnum("propagation"); 6 rbta.setPropagationBehavior(propagation.value()); 7 //解析isolation 8 Isolation isolation = attributes.getEnum("isolation"); 9 rbta.setIsolationLevel(isolation.value()); 10 //解析timeout 11 rbta.setTimeout(attributes.getNumber("timeout").intValue()); 12 //解析readOnly 13 rbta.setReadOnly(attributes.getBoolean("readOnly")); 14 //解析value 15 rbta.setQualifier(attributes.getString("value")); 16 17 //解析rollbackFor 18 List<RollbackRuleAttribute> rollbackRules = new ArrayList<>(); 19 for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) { 20 rollbackRules.add(new RollbackRuleAttribute(rbRule)); 21 } 22 //解析rollbackForClassName 23 for (String rbRule : attributes.getStringArray("rollbackForClassName")) { 24 rollbackRules.add(new RollbackRuleAttribute(rbRule)); 25 } 26 //解析noRollbackFor 27 for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) { 28 rollbackRules.add(new NoRollbackRuleAttribute(rbRule)); 29 } 30 //noRollbackForClassName 31 for (String rbRule : attributes.getStringArray("noRollbackForClassName")) { 32 rollbackRules.add(new NoRollbackRuleAttribute(rbRule)); 33 } 34 rbta.setRollbackRules(rollbackRules); 35 36 return rbta; 37 }
上面方法中實現了對對應類或者方法的事務屬性解析,你會在這個類中看到任何你常用或者不常用的屬性提取。
至此,我們終於完成了事務標籤的解析。我們是不是分析得太遠了,似乎已經忘記了從哪裡開始了。再回顧一下,我們現在的任務是找出某個增強器是否適合於對應的類,而是否匹配的關鍵則在於是否從指定的類或類中的方法中找到對應的事務屬性,現在,我們以UserServiceImple為例,已經在它的介面UserService中找到了事務屬性,所以,它是與事務增強器匹配的,也就是它會被事務功能修飾。
至此,事務功能的初始化工作便結束了,當判斷某個bean適用於事務增強時,也就是適用於增強器BeanFactoryTransactionAttributeSourceAdvisor。沒錯,還是這個類,所以說,在自定義標籤解析時,注入的類成為了整個事務功能的基礎。
BeanFactoryTransactionAttributeSourceAdvisor作為Advisor的實現類,自然要遵從Advisor的處理方式,當代理被呼叫時會呼叫這個類的增強方法,也就是此bean的Advisor,又因為在解析事務定義標籤時我們把TransactionInterceptor型別的bean注入到了BeanFactoryTransactionAttributeSourceAdvisor中,所以,在呼叫事務增強器增強的代理類時會首先執行TransactionInterceptor進行增強,同時,也就是TransactionInterceptor類的invoke方法中完成了整個事務的邏輯。
三、事務增強器
TransactionInterceptor支撐著整個事務功能的架構,邏輯還是相對複雜的,那麼現在我們切入正題來分析此攔截器是如何實現事務特性的。TransactionInterceptor類(package org.springframework.transaction.interceptor)繼承自MethodInterceptor,所以呼叫該類是從其invoke方法開始的:
1 public Object invoke(MethodInvocation invocation) throws Throwable { 2 // Work out the target class: may be {@code null}. 3 // The TransactionAttributeSource should be passed the target class 4 // as well as the method, which may be from an interface. 5 Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null); 6 7 // Adapt to TransactionAspectSupport's invokeWithinTransaction... 8 return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed); 9 }
其中又呼叫了其父類TransactionAspectSupport(package org.springframework.transaction.interceptor)的invokeWithinTransaction方法。
1 protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, 2 final InvocationCallback invocation) throws Throwable { 3 4 // If the transaction attribute is null, the method is non-transactional. 5 //獲取對應事務屬性 6 TransactionAttributeSource tas = getTransactionAttributeSource(); 7 final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null); 8 //獲取BeanFactory中的TransactionManager 9 final TransactionManager tm = determineTransactionManager(txAttr); 10 11 if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) { 12 ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> { 13 if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) { 14 throw new TransactionUsageException( 15 "Unsupported annotated transaction on suspending function detected: " + method + 16 ". Use TransactionalOperator.transactional extensions instead."); 17 } 18 ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(method.getReturnType()); 19 if (adapter == null) { 20 throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " + 21 method.getReturnType()); 22 } 23 return new ReactiveTransactionSupport(adapter); 24 }); 25 return txSupport.invokeWithinTransaction( 26 method, targetClass, invocation, txAttr, (ReactiveTransactionManager) tm); 27 } 28 29 PlatformTransactionManager ptm = asPlatformTransactionManager(tm); 30 //構造方法唯一標識(類.方法 如service.UserServiceImpl.save) 31 final String joinpointIdentification = methodIdentification(method, targetClass, txAttr); 32 33 //宣告式事務處理 34 if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) { 35 // Standard transaction demarcation with getTransaction and commit/rollback calls. 36 //建立TransactionInfo 37 TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification); 38 39 Object retVal; 40 try { 41 // This is an around advice: Invoke the next interceptor in the chain. 42 // This will normally result in a target object being invoked. 43 //執行被增強方法 44 retVal = invocation.proceedWithInvocation(); 45 } 46 catch (Throwable ex) { 47 // target invocation exception 48 //異常回滾 49 completeTransactionAfterThrowing(txInfo, ex); 50 throw ex; 51 } 52 finally { 53 //清除資訊 54 cleanupTransactionInfo(txInfo); 55 } 56 57 if (vavrPresent && VavrDelegate.isVavrTry(retVal)) { 58 // Set rollback-only in case of Vavr failure matching our rollback rules... 59 TransactionStatus status = txInfo.getTransactionStatus(); 60 if (status != null && txAttr != null) { 61 retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status); 62 } 63 } 64 65 //提交事務 66 commitTransactionAfterReturning(txInfo); 67 return retVal; 68 } 69 70 else { 71 final ThrowableHolder throwableHolder = new ThrowableHolder(); 72 73 // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in. 74 //程式設計式事務處理 75 try { 76 Object result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> { 77 TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status); 78 try { 79 Object retVal = invocation.proceedWithInvocation(); 80 if (vavrPresent && VavrDelegate.isVavrTry(retVal)) { 81 // Set rollback-only in case of Vavr failure matching our rollback rules... 82 retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status); 83 } 84 return retVal; 85 } 86 catch (Throwable ex) { 87 if (txAttr.rollbackOn(ex)) { 88 // A RuntimeException: will lead to a rollback. 89 if (ex instanceof RuntimeException) { 90 throw (RuntimeException) ex; 91 } 92 else { 93 throw new ThrowableHolderException(ex); 94 } 95 } 96 else { 97 // A normal return value: will lead to a commit. 98 throwableHolder.throwable = ex; 99 return null; 100 } 101 } 102 finally { 103 cleanupTransactionInfo(txInfo); 104 } 105 }); 106 107 // Check result state: It might indicate a Throwable to rethrow. 108 if (throwableHolder.throwable != null) { 109 throw throwableHolder.throwable; 110 } 111 return result; 112 } 113 catch (ThrowableHolderException ex) { 114 throw ex.getCause(); 115 } 116 catch (TransactionSystemException ex2) { 117 if (throwableHolder.throwable != null) { 118 logger.error("Application exception overridden by commit exception", throwableHolder.throwable); 119 ex2.initApplicationException(throwableHolder.throwable); 120 } 121 throw ex2; 122 } 123 catch (Throwable ex2) { 124 if (throwableHolder.throwable != null) { 125 logger.error("Application exception overridden by commit exception", throwableHolder.throwable); 126 } 127 throw ex2; 128 } 129 } 130 }
從上面的函式中,我們嘗試整理下事務處理的脈絡,在Spring中支援兩種事務處理的方式,分別是宣告式事務處理和程式設計式事務處理,兩者相對於開發人員來講差別很大,但是對於Spring中的實現來講,大同小異。在invoke中我們也可以看到這兩種方式的實現。考慮到對事務的應用比宣告式的事務處理使用起來方便,也相對流行些,我們就此種方式進行分析。對於宣告式的事務處理主要有以下幾個步驟。
① 獲取事務的屬性。
對於事務處理來說,最基礎或者最首要的工作便是獲取事務的屬性了。這是支撐整個事務功能的基石。如果沒有事務屬性,其他功能也就無從談起,在分析事務準備階段我們已經分析了事務屬性提取的功能,大家應該有所瞭解。
② 載入配置中配置的TransactionManager。
③ 不同的事務處理方式使用不同的邏輯。
對於宣告式事務的處理與程式設計式事務的處理,第一點區別在於事務屬性上,因為程式設計式的事務處理是不需要有事務屬性的,第二點區別就是在TransactionManager上,CallbackPreferringPlatformTransactionManager實現了PlatformTransactionManager介面,暴露出一個方法用於執行事務處理中的回撥。所以,這兩種方式都可以用作事務處理方式的判斷。
④ 在目標方法執行前獲取事務並收集事務資訊。
事務資訊與事務屬性並不相同,也就是TransactionInfo與TransactionAttribute並不相同,TransactionInfo包含TransactionAttribute資訊,但是,除了TransactionAttribute外還有其他事務資訊,例如PlatformTransactionManager以及TransactionStatus相關資訊。
⑤ 執行目標方法。
⑥ 一旦出現異常,嘗試異常處理。
⑦ 提交事務前的事務資訊清除。
⑧ 提交事務。
上面的步驟分析旨在讓大家對事務功能與步驟有個大致的瞭解,具體的功能還需要詳細地分析。
(一)建立事務
我們先分析事務建立的過程。TransactionAspectSupport類(package org.springframework.transaction.interceptor)的createTransactionIfNecessary方法:
1 protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm, 2 @Nullable TransactionAttribute txAttr, final String joinpointIdentification) { 3 4 // If no name specified, apply method identification as transaction name. 5 //如果沒有名稱指定則使用方法唯一標識,並使用DelegatingTransactionAttribute封裝txAttr 6 if (txAttr != null && txAttr.getName() == null) { 7 txAttr = new DelegatingTransactionAttribute(txAttr) { 8 @Override 9 public String getName() { 10 return joinpointIdentification; 11 } 12 }; 13 } 14 15 TransactionStatus status = null; 16 if (txAttr != null) { 17 if (tm != null) { 18 //獲取TransactionStatus 19 status = tm.getTransaction(txAttr); 20 } 21 else { 22 if (logger.isDebugEnabled()) { 23 logger.debug("Skipping transactional joinpoint [" + joinpointIdentification + 24 "] because no transaction manager has been configured"); 25 } 26 } 27 } 28 //根據指定的屬性與status準備一個TransactionInfo 29 return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status); 30 }
對於createTransactionIfNecessary函式主要做了這樣幾件事情。
① 使用DelegatingTransactionAttribute封裝傳入的TransactionAttribute例項。
對於傳入的TransactionAttribute型別的引數txAttr,當前的實際型別是RuleBasedTransactionAttribute,是由獲取事務屬性時生成的,主要用於資料承載,而這裡之所以使用DelegatingTransactionAttribute進行封裝,當時是提供了更多的功能。
② 獲取事務
事務處理當然是以事務為核心,那麼獲取事務就是最重要的事情。
③ 構建事務資訊
根據之前幾個步驟獲取的資訊構建TransactionInfo並返回。
我們分別對以上步驟進行詳細的解析。
(1)獲取事務
Spring中使用getTransaction來處理事務的準備工作,包括事務獲取以及資訊的構建。getTransaction函式在實現PlatformTransactionManager介面的AbstractPlatformTransactionManager抽象類(package org.springframework.transaction.support)中給出了具體實現方法:
1 public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) 2 throws TransactionException { 3 4 // Use defaults if no transaction definition given. 5 TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults()); 6 7 Object transaction = doGetTransaction(); 8 boolean debugEnabled = logger.isDebugEnabled(); 9 10 //判斷當前執行緒是否存在事務,判讀依據為當前執行緒記錄的連線不為空且連線中(connectionHolder)中的transactionActive屬性不為空 11 if (isExistingTransaction(transaction)) { 12 // Existing transaction found -> check propagation behavior to find out how to behave. 13 //當前執行緒已經存在事務 14 return handleExistingTransaction(def, transaction, debugEnabled); 15 } 16 17 // Check definition settings for new transaction. 18 //事務超時設定驗證 19 if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) { 20 throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout()); 21 } 22 23 // No existing transaction found -> check propagation behavior to find out how to proceed. 24 //如果當前執行緒不存在事務,但是PropagationBehavior卻被宣告為PROPAGATION_MANDATORY丟擲異常 25 if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) { 26 throw new IllegalTransactionStateException( 27 "No existing transaction found for transaction marked with propagation 'mandatory'"); 28 } 29 else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED || 30 def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW || 31 def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) { 32 //PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED都需要新疆事務 33 //空掛起 34 SuspendedResourcesHolder suspendedResources = suspend(null); 35 if (debugEnabled) { 36 logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def); 37 } 38 try { 39 return startTransaction(def, transaction, debugEnabled, suspendedResources); 40 } 41 catch (RuntimeException | Error ex) { 42 resume(null, suspendedResources); 43 throw ex; 44 } 45 } 46 else { 47 // Create "empty" transaction: no actual transaction, but potentially synchronization. 48 if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) { 49 logger.warn("Custom isolation level specified but no actual transaction initiated; " + 50 "isolation level will effectively be ignored: " + def); 51 } 52 boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS); 53 return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null); 54 } 55 }
上面函式呼叫了本類中的startTransaction函式:
1 private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction, 2 boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) { 3 4 boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER); 5 DefaultTransact