本文參考:《Spring源碼深度解析》及源碼走讀.培養源碼閱讀思想
文章目錄
- 1.必須懂的幾個類
- 2.1 提取器驅動(裝載)的advisor:BeanFactoryTransactionAttributeSourceAdvisor
- 2.2 @Transation註解元數據提取器:TransactionAttributeSource
- 2.3 事務執行器\攔截器:TransactionInterceptor
- 2. 事務管理入口
- 3. 構造器:事務攔截器基本配置查找與生成代理
- 4. 事務攔截器
先放圖,du害一下大家,
1.必須懂的幾個類
試想一下,如果Connection支持事務提交回滾(底層支持),那麼你如何來設計你的事務處理框架?
我相信很多人的想法都是
- 先讀取 @Transation註解的屬性.生成一個對象(存放事務相關)
- 根據得到的該對象進行事務的commit,失敗回滾,最終事務清除.
Spring框架對事務的支持大概也是這樣的步驟,Spring支持嵌入事務,即方法中嵌套方法,如果都支持事務,則在裏面的事務結束或者失敗之後,外面的事務繼續執行.
我們剛纔提到 @Transation註解的屬性提取,那麼必定需要這樣一個類去做提取的操作,提取的對象存儲也需要一個相應類,用什麼方式執行事務,這些都是我們後面需要討論的內容,但是,在此之前,我們先看幾個類,我們已經知道了實現事務的大概步驟,那麼我們需要來看一下,Spring怎麼去實現這些步驟的.
2.1 提取器驅動(裝載)的advisor:BeanFactoryTransactionAttributeSourceAdvisor
我們知道Spring框架大量的使用了接口,可以想象,對於 @Transation註解的提取,Spring必定也是通過接口的實現類來定義提取方法(下一個會講到),所以我們可以想象,我們需要一個類來承接這些接口和其他的屬性.我們這裏要講的就是這個類。
我們看一下類上的註解:
- Advisor driven by a TransactionAttributeSource, used to include a transaction advice bean for methods that are transactional.
包含一個 TransactionAttributeSource,用於事務通知。我們暫且不管 TransactionAttributeSource類的作用,目前我們可以知道的就是BeanFactoryTransactionAttributeSourceAdvisor他會裝載和提供一個 TransactionAttributeSource類。
我們看他是怎麼實現 TransactionAttributeSource的。
@SuppressWarnings("serial")
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
//這個就是我們念念不忘的TransactionAttributeSource
private TransactionAttributeSource transactionAttributeSource;
//因爲BeanFactoryTransactionAttributeSourceAdvisor 繼承了PointCut接口,所以需要實現getPointCut方法
//而獲取到的PointCut類會返回我們需要的TransactionAttributeSource。
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@Override
protected TransactionAttributeSource getTransactionAttributeSource() {
return transactionAttributeSource;
}
};
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
}
很容易我們看到了TransactionAttributeSource 這個類,並且因爲BeanFactoryTransactionAttributeSourceAdvisor繼承了Pointcut接口,需要實現getPointcut方法,相當於是
通過得到PointCut實現類,再獲取TransactionAttributeSource
2.2 @Transation註解元數據提取器:TransactionAttributeSource
@Transation的提取需要一定的規則,而不同的方式可能對應不同的規則,所以Spring利用接口的方式,制定提取的抽象。通過繼承實現不同的提取規則。
首先你要知道 TransactionAttributeSource是一個接口,我們看一下類的描述
- Strategy interface used by TransactionInterceptor for metadata retrieval.
Implementations know how to source transaction attributes, whether from configuration, metadata attributes at source level (such as Java 5 annotations), or anywhere else.
提供給TransactionInterceptor攔截器用於事務元數據提取的接口.
但是接口需要實現類,因爲是註解解析,這邊的具體實現類是 AnnotationTransactionAttributeSource
作爲一個註解提取器, AnnotationTransactionAttributeSource如何實現提取呢?
3.1 真實註解處理器:TransactionAnnotationParser
這邊就給你答案,那就是TransactionAnnotationParser,看到該類的構造方法.必定會注入SpringTransactionAnnotationParser,這個類,這也是我們後面處理註解需要注意的。
public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
this.publicMethodsOnly = publicMethodsOnly;
this.annotationParsers = new LinkedHashSet<TransactionAnnotationParser>(2);
this.annotationParsers.add(new SpringTransactionAnnotationParser());
if (jta12Present) {
this.annotationParsers.add(new JtaTransactionAnnotationParser());
}
if (ejb3Present) {
this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
}
}
2.3 事務執行器\攔截器:TransactionInterceptor
首先知道一點就是 ****實現了 MethodInterceptor接口,需要實現這個類的 invoke方法,事務處理的具體邏輯就在這裏,而 MethodInterceptor又會在代理創建的時候被調用,所以我們基本知道該攔截器實現事務管理是通過invoke方法在代理的時候實現。
我們在後面的描述中會講到具體實現,彆着急
關注一下類上的註釋:
- AOP Alliance MethodInterceptor for declarative transaction management using the common Spring transaction infrastructure (PlatformTransactionManager)
- TransactionInterceptors are thread-safe.
事務管理和線程安全
2. 事務管理入口
2.1 註解式
還記得開啓事務的註解式什麼嗎?我錯,我知道你不記得了。
開啓事務的註解是 EnableTransactionManagement,我們可以查看一下這個註解的使用,
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;
//實現事務的方式(proxy或者aspectj)
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
很好,我們看到這個註解有一個mode,能夠配置事務管理實現的方式,默認是PROXY.
在註解上面有一個 @Import註解,如果你告訴我不懂,我就是一巴掌過去. @Import註解引入一個Selector類,我們要看一下他是做什麼幺蛾子的。
3.1 事務管理選擇器:TransactionManagementConfigurationSelector
這個註解繼承了AdviceModeImportSelector,實現selectImport方法,朔本回源,在Mvc啓動的時候會調用Selector,也就是這樣啓動的.這邊我們不細究,知道一個大概:
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[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}
這裏看到了AdviceMode 的選擇,我們只分析PROXY的方式,不要問爲什麼,問就是我菜.
PROXY的方式會返回兩個類:AutoProxyRegistrar和ProxyTransactionManagementConfiguration
幺蛾子就出在這裏面.
4.1 註冊代理構造器:AutoProxyRegistrar
這個類只有一個方法,這個方法會去註冊一些BeanDefinition.
@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);
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) {
//重要的地方我只看到這裏
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
}
雖然這個類嘰裏呱啦的說了一堆,但是重要的是這一行代碼,這個方法會爲我們註冊一個很重要的類:InfrastructureAdvisorAutoProxyCreator,自動代理構造器,我們對於advisor的查找和代理的實現都在這個類中實現,後面我們會說道。
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAutoProxyCreatorIfNecessary(registry, null);
}
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}
4.2 事務註解驅動配置:ProxyTransactionManagementConfiguration
這個類,會爲我們註冊幾個Bean,就是我們一開頭說的,事務註解元數據提取器、事務處理攔截器、提取器承載類
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
//事務註解提取器的承載類
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
//注入事務註解提取器
advisor.setTransactionAttributeSource(transactionAttributeSource());
//注入攔截器
advisor.setAdvice(transactionInterceptor());
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
return advisor;
}
//事務註解提取器
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
//事務註解提取器的具體實現
return new AnnotationTransactionAttributeSource();
}
//攔截器
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor() {
TransactionInterceptor interceptor = new TransactionInterceptor();
//注入事務註解提取器
interceptor.setTransactionAttributeSource(transactionAttributeSource());
if (this.txManager != null) {
//事務管理器:PlatformTransactionManager
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
2.2 XML式
3.1 事務命名空間處理器:TxNamespaceHandler
這個類實現了NameSpaceHandler,Spring框架會實現NamespaceHandler接口實現類的調用,這個我們暫時不管他。
可以想象到,和註解處理的方式應該類似,這邊也應該注入,我們剛纔講的三個類.所以我們來看一下代碼實現
@Override
public void init() {
registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
}
這邊註冊了三個BeanDefinitionParser的類,用屁股想象都知道,他大概想要去做什麼事情,但是我們還是一個一個來看一下.
4.1 TxAdviceBeanDefinitionParser:註冊事務註解提取器(或直接讀取事務配置)
看到這邊會去提取xml的元素,然後判斷是否手動在XML中寫入了事務相關屬性,parseAttributeSource這個方法會去解析相關的屬性(只讀、超時時間…)
如果不是xml方式去注入的話,就需要去註冊一個AnnotationTransactionAttributeSource,讓這個類去提取**@Transational**上的屬性,然後生成對應類.
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
builder.addPropertyReference("transactionManager", TxNamespaceHandler.getTransactionManagerName(element));
List<Element> txAttributes = DomUtils.getChildElementsByTagName(element, ATTRIBUTES_ELEMENT);
if (txAttributes.size() > 1) {
parserContext.getReaderContext().error(
"Element <attributes> is allowed at most once inside element <advice>", element);
}
else if (txAttributes.size() == 1) {
// Using attributes source.
Element attributeSourceElement = txAttributes.get(0);
RootBeanDefinition attributeSourceDefinition = parseAttributeSource(attributeSourceElement, parserContext);
builder.addPropertyValue("transactionAttributeSource", attributeSourceDefinition);
}
else {
// Assume annotations source.
builder.addPropertyValue("transactionAttributeSource",
new RootBeanDefinition("org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"));
}
}
4.2 註冊事務基礎Bean配置
等下我們看代碼的時候你會發現,他實現了和事務註解驅動配置:ProxyTransactionManagementConfiguration類似的功能:
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
registerTransactionalEventListenerFactory(parserContext);
String mode = element.getAttribute("mode");
if ("aspectj".equals(mode)) {
// mode="aspectj"
registerTransactionAspect(element, parserContext);
}
else {
// mode="proxy"
AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
}
return null;
}
這邊我們依然只看PROXY的方式,我們可以看到下面的代碼基本可以分成四步:
- AopNamespaceUtils.registerAutoProxyCreatorIfNecessary:註冊InfrastructureAdvisorAutoProxyCreator以及xml配置的解析,不具體看了
- 注入AnnotationTransactionAttributeSource
- 注入TransactionInterceptor
- 注入BeanFactoryTransactionAttributeSourceAdvisor
- 註冊上述的組件到context
public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
//註冊InfrastructureAdvisorAutoProxyCreator類和解析XML屬性
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
Object eleSource = parserContext.extractSource(element);
//注入AnnotationTransactionAttributeSource
RootBeanDefinition sourceDef = new RootBeanDefinition(
"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
sourceDef.setSource(eleSource);
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
//注入TransactionInterceptor
RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
interceptorDef.setSource(eleSource);
interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registerTransactionManager(element, interceptorDef);
interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
//注入BeanFactoryTransactionAttributeSourceAdvisor
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);
//註冊到context
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);
}
}
}
4.3 註冊事務管理器
這個類應該是解析xml上面的註解來註冊事務管理器的,我們看一下這邊的註釋
- Parser for the tx:jta-transaction-manager/ XML configuration element, autodetecting WebLogic and WebSphere servers and exposing the corresponding JtaTransactionManager subclass.
代碼裏面會根據不同的方式去註冊事務管理器.
static String resolveJtaTransactionManagerClassName() {
if (weblogicPresent) {
return WEBLOGIC_JTA_TRANSACTION_MANAGER_CLASS_NAME;
}
else if (webspherePresent) {
return WEBSPHERE_TRANSACTION_MANAGER_CLASS_NAME;
}
else {
return JTA_TRANSACTION_MANAGER_CLASS_NAME;
}
}
3. 構造器:事務攔截器基本配置查找與生成代理
廢話不多說,我們來看一下InfrastructureAdvisorAutoProxyCreator這個類,這個類隔代實現了BeanPostProcessor接口,對於BeanPostProcessor,我們看一下類的註釋
- Factory hook that allows for custom modification of new bean instances, e.g. checking for marker interfaces or wrapping them with proxies.
大概就是爲Bean工廠創建的Bean實例提供一個鉤子,在Bean調用之前做一些修飾操作.
實現postProcessAfterInitialization才能實現上面所說的操作,我們看一下這個方法:
注意類上的註釋:通過配置監聽器實現代理,這邊設置緩存用過特定key查找,沒有找到會進入wrapIfNecessary方法,根據註釋,我們可以知道,這個方法大概就是要去生成一個代理了。
/**
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
* @see #getAdvicesAndAdvisorsForBean
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
通過一些列的查找,如果找到對應的代理類就直接返回,否則
- 先去查找攔截器
- 在通過攔截器實現代理
/**
* Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
* @param bean the raw bean instance
* @param beanName the name of the bean
* @param cacheKey the cache key for metadata access
* @return a proxy wrapping the bean, or the raw bean instance as-is
*/
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 查找攔截器
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
//生成代理
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
我們下面通過這兩部分來分析一下
2.1 攔截器查找
這裏進入攔截器的查找,如果查找到的攔截器爲空, 返回空數組,否則返回攔截器數組
@Override
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
查找過程又分成兩步
- 查找所有攔截器
- 根據找到的所有攔截器,查找合適的攔截器
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
3.1 查找所有攔截器
這邊的這個方法處理是這樣的
- 從BeanFactory(或者緩存數組)中拿到advisor的字符串名稱
- 進行一些判斷,然後從BeanFactory裏面獲取Advisor實例
- 組裝List返回
雖然我不知道BeanFactory怎麼去拿到這些advisor,能力有限,以後再看,但是我們剛纔開篇註冊的三個Advisor這邊應該是可以拿到的。
public List<Advisor> findAdvisorBeans() {
String[] advisorNames = null;
synchronized (this) {
advisorNames = this.cachedAdvisorBeanNames;
//從BeanFactory(或者緩存數組)中拿到advisor的字符串名稱
if (advisorNames == null) {
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
}
if (advisorNames.length == 0) {
return new LinkedList<Advisor>();
}
List<Advisor> advisors = new LinkedList<Advisor>();
for (String name : advisorNames) {
if (isEligibleBean(name)) {
if (this.beanFactory.isCurrentlyInCreation(name)) {
//......................省略
//進行一些判斷,然後從BeanFactory裏面獲取Advisor實例
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
}
}
}
return advisors;
}
3.2 根據找到的所有攔截器,查找合適的攔截器
這一步的操作關鍵的代碼在這邊,我們捨去一些操作,直接來看是怎麼查找ApplyAdvisor的
AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
這邊有一種Advisor叫做IntroductionAdvisor ,這個接口網上說好像是類級別上的增強,具體可以查閱對應資料,但是我們這邊不關注這個類.
我們這邊需要關注的是canApply這個方法,因爲他是判斷Advisor是否適用於當前事務管理的依據.
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
往下看,這邊可以看到,第二個if判斷判斷了類是否是PointcutAdvisor,剛纔上面介紹的BeanFactoryTransactionAttributeSourceAdvisor類就是實現了PointcutAdvisor接口,所以這邊他要起到作用了.
這邊傳入getPointcut方法返回的對象,在上面的介紹中說到,內部實現了TransactionAttributeSourcePointcut
即當前的getPointcut方法傳入TransactionAttributeSourcePointcut
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
return true;
}
}
canApply方法需要關注兩個地方
- MethodMatcher的獲取
- 調用matches方法
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
//MethodMatcher的獲取
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
//循環通過MethodMatcher的matches方法匹配
Set<Class<?>> classes = new LinkedHashSet<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
classes.add(targetClass);
for (Class<?> clazz : classes) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
if ((introductionAwareMethodMatcher != null &&
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
4.1 獲取方法匹配器:MethodMatcher
上面說的,傳入的pointcut是TransactionAttributeSourcePointcut類,所以直接查看這個類是怎麼獲取MethodMatcher的:
@Override
public final MethodMatcher getMethodMatcher() {
return this;
}
這邊看到實現的getMethodMatcher方法直接返回this,也就是說,返回的Match就是TransactionAttributeSourcePointcut…
4.2 方法匹配器匹配,返回結果
既然我們已經知道了MethodMatcher,就要去看一下matchs到底是怎麼匹配的.
@Override
public boolean matches(Method method, Class<?> targetClass) {
if (TransactionalProxy.class.isAssignableFrom(targetClass)) {
return false;
}
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
從剛纔的分析可以看到,這邊拿到的TransactionAttributeSourcePointcut是BeanFactoryTransactionAttributeSourceAdvisor類中的內部類,並實現了getTransactionAttributeSource方法.
可以參考上面介紹BeanFactoryTransactionAttributeSourceAdvisor,這裏的TransactionAttributeSource注入的是AnnotationTransactionAttributeSource
所以我們來看一下這邊的實現,依然是先通過緩存去獲取,如果沒有獲取到纔去解析。那麼如何解析呢.
@Override
public TransactionAttribute getTransactionAttribute(Method method, Class<?> targetClass) {
Object cacheKey = getCacheKey(method, targetClass);
Object cached = this.attributeCache.get(cacheKey);
if (cached != null) {
if (cached == NULL_TRANSACTION_ATTRIBUTE) {
return null;
}
else {
return (TransactionAttribute) cached;
}
}
else {
TransactionAttribute txAtt = computeTransactionAttribute(method, targetClass);
// Put it in the cache.
if (txAtt == null) {
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
}
else {
if (logger.isDebugEnabled()) {
Class<?> classToLog = (targetClass != null ? targetClass : method.getDeclaringClass());
logger.debug("Adding transactional method '" + classToLog.getSimpleName() + "." +
method.getName() + "' with attribute: " + txAtt);
}
this.attributeCache.put(cacheKey, txAtt);
}
return txAtt;
}
}
5.1 解析@Transation註解
這邊的解析分成四種情況,任意一種滿足則退出,方法上的註釋也說明了這些:
- 解析當前方法上的註解
- 解析當前類上的註解
- 解析類實現的接口的方法上的註解
- 解析類實現的接口上的註解
protected TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) {
// Don't allow no-public methods as required.
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
// Ignore CGLIB subclasses - introspect the actual user class.
Class<?> userClass = ClassUtils.getUserClass(targetClass);
// The method may be on an interface, but we need attributes from the target class.
// If the target class is null, the method will be unchanged.
Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass);
// If we are dealing with method with generic parameters, find the original method.
specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
// First try is the method in the target class.
TransactionAttribute txAtt = findTransactionAttribute(specificMethod);
if (txAtt != null) {
return txAtt;
}
// Second try is the transaction attribute on the target class.
txAtt = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAtt != null && ClassUtils.isUserLevelMethod(method)) {
return txAtt;
}
if (specificMethod != method) {
// Fallback is to look at the original method.
txAtt = findTransactionAttribute(method);
if (txAtt != null) {
return txAtt;
}
// Last fallback is the class of the original method.
txAtt = findTransactionAttribute(method.getDeclaringClass());
if (txAtt != null && ClassUtils.isUserLevelMethod(method)) {
return txAtt;
}
}
return null;
}
解析的步驟不是重點,重點是如何去解析.
可以看到這邊會拿到註解,然後循環查找合適的事務註解去解析並返回.
我們剛纔看到在 AnnotationTransactionAttributeSource中會初始化SpringTransactionAnnotationParser對象
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) {
if (ae.getAnnotations().length > 0) {
for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
TransactionAttribute attr = annotationParser.parseTransactionAnnotation(ae);
if (attr != null) {
return attr;
}
}
}
return null;
}
這邊即通過SpringTransactionAnnotationParser來解析@Trasation註解,看一下代碼即可,不重點分析
@Override
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ae, Transactional.class);
if (attributes != null) {
return parseTransactionAnnotation(attributes);
}
else {
return null;
}
}
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
Propagation propagation = attributes.getEnum("propagation");
rbta.setPropagationBehavior(propagation.value());
Isolation isolation = attributes.getEnum("isolation");
rbta.setIsolationLevel(isolation.value());
rbta.setTimeout(attributes.getNumber("timeout").intValue());
rbta.setReadOnly(attributes.getBoolean("readOnly"));
rbta.setQualifier(attributes.getString("value"));
ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<RollbackRuleAttribute>();
Class<?>[] rbf = attributes.getClassArray("rollbackFor");
for (Class<?> rbRule : rbf) {
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
String[] rbfc = attributes.getStringArray("rollbackForClassName");
for (String rbRule : rbfc) {
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
Class<?>[] nrbf = attributes.getClassArray("noRollbackFor");
for (Class<?> rbRule : nrbf) {
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
String[] nrbfc = attributes.getStringArray("noRollbackForClassName");
for (String rbRule : nrbfc) {
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
rbta.getRollbackRules().addAll(rollBackRules);
return rbta;
}
2.2 生成代理
上面的步驟結束,已經拿到所有類和方法對應的攔截器數組.即生成代理.
這邊不贅述,參考另一篇博文:Spring代理創建和代理實現
4. 事務攔截器
2.1 需要懂的事務相關的幾個類
3.1 事務信息承載器:TransactionInfo
看一下注釋的內容:
- Opaque object used to hold Transaction information. Subclasses must pass it back to methods on this class, but not see its internals.
這個類其實是用來承載解析出來的事務屬性集、事務狀態的類。記錄事務的信息主要是在事務執行的生命週期中,Spring可以把控當前事務。他的內部包含了下面幾個類。
protected final class TransactionInfo {
private final PlatformTransactionManager transactionManager;
private final TransactionAttribute transactionAttribute;
private final String joinpointIdentification;
private TransactionStatus transactionStatus;
private TransactionInfo oldTransactionInfo;
}
3.2 事務屬性:TransactionAttribute
剛纔上面的解析器Parse代碼裏面已經說明,這個類是用來承載**@Transaction**註解帶來的屬性的.
3.3 事務狀態:TransactionStatus
這個接口是操作事務最關鍵的類,它能夠實現保存點操作、判斷事務狀態等.具體實現在後面的描述中給出
看一下接口上的註釋:
- programmatically request a rollback (instead of throwing an exception that causes an implicit rollback).
- Derives from the SavepointManager interface to provide access to savepoint management facilities. Note that savepoint management is only available if supported by the underlying transaction manager.
2.2 事務攔截器實現
事務攔截器實現了MethodInterceptor,上面生成代理的時候會把TransactionInterceptor添加到對應calss的method中.
現在分析一下他的實現:
關注invoke方法:
@Override
public Object invoke(final MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {@code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
@Override
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
});
}
重寫了proceedWithInvocation()方法,調用傳入的MethodInvocation的proceed方法.
可以這樣理解,傳進來的MethodInvoke代表某個正在執行的業務方法或者事務(嵌套事務),那麼事務執行的操作應該是這樣的
{
事務開始
try{
執行業務方法、或者嵌入事務.
}catch{
回滾操作
}finally{
事務提交、狀態清除等.
}
}
我們具體看一下代碼:
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
//事務的標識
final String joinpointIdentification = methodIdentification(method, targetClass);
//聲明式事務
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
//開啓事務
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
//執行具體方法
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
//事務回滾
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
//清理操作
cleanupTransactionInfo(txInfo);
}
//事務提交
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
//編程式事務不管
try {
Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
new TransactionCallback<Object>() {
}
}
}
}
我們從上面代碼可以看到基本是這樣的情況,這邊只分析聲明式事務的處理.
3.1 構造事務信息承載器:TransactionInfo
事務信息承載,最重要的是TransationStatus,所以這邊的代碼分兩個步驟:
- 獲取TransationStatus
- 構造TransactionInfo
protected TransactionInfo createTransactionIfNecessary(
PlatformTransactionManager tm, TransactionAttribute txAttr, final String joinpointIdentification) {
// If no name specified, apply method identification as transaction name.
if (txAttr != null && txAttr.getName() == null) {
txAttr = new DelegatingTransactionAttribute(txAttr) {
@Override
public String getName() {
return joinpointIdentification;
}
};
}
//獲取事務狀態
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
status = tm.getTransaction(txAttr);
}
else {
//日誌
}
}
//構造TransactionInfo
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
3.2 獲取TransationStatus
這邊通過傳入的TransationAttribute實現事務的管理。分爲三個重要的步驟:拿到事務對象、判斷當前存在事務和不存在事務
@Override
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
//拿到事務對象
Object transaction = doGetTransaction();
//存在事務
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(definition, transaction, debugEnabled);
}
//是否超時
if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
}
//不存在事務
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
}
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
//開始事務
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException ex) {
resume(null, suspendedResources);
throw ex;
}
catch (Error err) {
resume(null, suspendedResources);
throw err;
}
}
else {
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
}
}
4.1 拿到事務對象
設置保存點,獲取相應資源
@Override
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
4.2 存在事務
存在事務的情況,這邊會根據Spring定義的事務的傳播狀態去處理,分別爲:
- 不支持事務:報錯
- 執行非事務處理,如果存在的話,暫停當前事務(掛起)
- 如果新事務的傳播機制是RequireNew,把正在執行的事務掛起.
- 嵌入式事務
- 支持設置保存點,創建保存點
- 不支持設置保存點,掛起當前事務執行新事務
保存點可以通過Connection來處理,這邊不關心底層的實現
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
//不支持事務:報錯
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
//執行非事務處理,如果存在的話,暫停當前事務(掛起)
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
//如果新事務的傳播機制是RequireNew,把正在執行的事務掛起.
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
catch (Error beginErr) {
resumeAfterBeginException(transaction, suspendedResources, beginErr);
throw beginErr;
}
}
//嵌入式事務 支持設置保存點,創建保存點
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
if (!isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException(
"Transaction manager does not allow nested transactions by default - " +
"specify 'nestedTransactionAllowed' property with value 'true'");
}
if (useSavepointForNestedTransaction()) {
DefaultTransactionStatus status = prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
status.createAndHoldSavepoint();
return status;
}
else {
//不支持設置保存點,掛起當前事務執行新事務
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, null);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
}
//..............略
}
5.1 設置Spring管理Connection及屬性
doBegin方法獲取連接,交由Spring管理,主要關注DataSourceTransactionManager這個類的具體實現包括下面幾個部分:
- 嘗試獲取連接,獲取不到則創建連接
- 設置事務隔離級別
- 更改自動提交設置,將提交給Spring實現
- 激活事務、設置超時時間
- 將連接綁定到當前線程
- 如果異常,釋放連接
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
//嘗試獲取連接,獲取不到則創建連接
if (txObject.getConnectionHolder() == null || txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
Connection newCon = this.dataSource.getConnection();
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
//設置事務隔離級別
Integer previousIsolationLevel = org.springframework.jdbc.datasource.DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
//更改自動提交設置,將提交給Spring實現
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
con.setAutoCommit(false);
}
//激活事務、設置超時時間
txObject.getConnectionHolder().setTransactionActive(true);
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
if (txObject.isNewConnectionHolder()) {
//將連接綁定到當前線程
TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
}
}
catch (Throwable ex) {
if (txObject.isNewConnectionHolder()) {
//異常釋放連接
org.springframework.jdbc.datasource.DataSourceUtils.releaseConnection(con, this.dataSource);
txObject.setConnectionHolder(null, false);
}
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}
5.2 將事務信息記錄到事務隊列管理器
protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
/**
* 如果是新的事務,要把事務信息記錄到事務管理器中
*/
if (status.isNewSynchronization()) {
TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction());
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(
definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT ?
definition.getIsolationLevel() : null);
TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
TransactionSynchronizationManager.initSynchronization();
}
}
4.3 不存在事務
5.1 設置Spring管理Connection及屬性
同上
5.2 將事務信息記錄到事務隊列管理器
同上
3.3 構造TransactionInfo
這邊比較關鍵的一步就是綁定事務到線程.從註釋上面看,是爲了正確管理,即使沒有創建事務的情況。
而bindToThread其實是維護了一個ThreadLocal的變量。
*/
protected TransactionInfo prepareTransactionInfo(PlatformTransactionManager tm,
TransactionAttribute txAttr, String joinpointIdentification, TransactionStatus status) {
//構造TransactionInfo
TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
if (txAttr != null) {
txInfo.newTransactionStatus(status);
}
else {
//日誌
}
// We always bind the TransactionInfo to the thread, even if we didn't create
// a new transaction here. This guarantees that the TransactionInfo stack
// will be managed correctly even if no transaction was created by this aspect.
//綁定到線程
txInfo.bindToThread();
return txInfo;
}
2.3 執行相應業務方法
這一步就是方法的調用,沒有特別指的分析的地方:
return invocation.proceedWithInvocation();
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
@Override
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
});
2.4 事務異常處理
事務異常分成兩種情況,如果拋出RunTimeException和Error直接回滾,其他異常會嘗試提交
protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) {
/**
* 57.當拋出異常時首先判斷當前是否存在事務,這是基本依據
*/
if (txInfo != null && txInfo.hasTransaction()) {
//對於RunTimeException或Error的異常會終止提交
if (txInfo.transactionAttribute.rollbackOn(ex)) {
try {
//回滾操作
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {.//.....略
}
}
//其他的異常依然會操作提交
else {
try {
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
//........略}
}
}
}
3.1 事務回滾
事務回滾會先判斷狀態,如果已經提交(有這種情況?),直接報錯,不然利用Connection的Api處理回滾
@Override
public final void rollback(TransactionStatus status) throws TransactionException {
//如果事務已經提交,回滾報錯
if (status.isCompleted()) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
//處理回滾
processRollback(defStatus);
}
回滾分成幾種情況
- 通過保存點進行回滾
- 新事務通過Connection的api調用回覆
- 其他則設值回滾標識
- 事務處理結束之後的信息清除
private void processRollback(DefaultTransactionStatus status) {
try {
try {
/**
* 自定義觸發器的調用,註冊參考
* @see TransactionSynchronizationManager#registerSynchronization(TransactionSynchronization)
*/
triggerBeforeCompletion(status);
//通過保存點信息進行回滾
if (status.hasSavepoint()) {
status.rollbackToHeldSavepoint();
}
//如果是新的事務,直接回滾,這邊也是通過Connection回滾
else if (status.isNewTransaction()) {
doRollback(status);
}
else if (status.hasTransaction()) {
if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
//標記爲回滾狀態,下一次執行的時候回滾
doSetRollbackOnly(status);
}
else {
//..............
}
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
}
finally {
//事務處理結束之後的信息清除
cleanupAfterCompletion(status);
}
}
通過保存點回滾也是直接調用Connection的api,如下:
//從保存點回滾
conHolder.getConnection().rollback((Savepoint) savepoint);
//釋放保存點
conHolder.getConnection().release((Savepoint) savepoint);
事務處理結束之後的信息清除和事務提交之後的finally操作一樣,這邊不贅述,往後看
2.5 TransactionInfo清除
重置TransactionInfo
/**
* Reset the TransactionInfo ThreadLocal.
* <p>Call this in all cases: exception or normal return!
*/
protected void cleanupTransactionInfo(TransactionInfo txInfo) {
if (txInfo != null) {
txInfo.restoreThreadLocalStatus();
}
}
2.6 事務提交
事務提交這邊也分爲幾種情況:
- 事務已經提交,報錯
- 標記爲回滾,調用回滾方法(回滾方法中有一步處理就是設置這個標識)
- 提交
public final void commit(TransactionStatus status) throws TransactionException {
//事務已提交,報錯
if (status.isCompleted()) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
//如果事務中已經被標記爲回滾,則不嘗試提交,直接回滾。
if (defStatus.isLocalRollbackOnly()) {
processRollback(defStatus);
return;
}
if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
processRollback(defStatus);
if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {
throw new UnexpectedRollbackException(
"Transaction rolled back because it has been marked as rollback-only");
}
return;
}
//處理事務提交
processCommit(defStatus);
}
這邊主要分成幾步:
- 存在保存點,說明有事務沒有執行完不提交
- 如果是新事務,說明事務執行完成了,調用Connectio.commit提交事務
- 其他情況不提交,報錯回滾或者拋錯
- finally清除操作
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
boolean beforeCompletionInvoked = false;
try {
prepareForCommit(status);
triggerBeforeCommit(status);
triggerBeforeCompletion(status);
beforeCompletionInvoked = true;
boolean globalRollbackOnly = false;
if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {
globalRollbackOnly = status.isGlobalRollbackOnly();
}
if (status.hasSavepoint()) {
//存在保存點則清除,但不提交事務
status.releaseHeldSavepoint();
}
else if (status.isNewTransaction()) {
//獨立新事務的提交---非獨立新事物不提交
doCommit(status);
}
try {
triggerAfterCommit(status);
}
finally {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
}
}
finally {
/**
* 83.提交後清除操作
*/
cleanupAfterCompletion(status);
}
}
finally清除操作主要分成下面幾步:
- 修改事務狀態
- 新事務連接釋放
- 如果有事務被掛起,則喚醒對應事務
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
//修改事務狀態
status.setCompleted();
if (status.isNewSynchronization()) {
//清除當前事務的同步信息
TransactionSynchronizationManager.clear();
}
if (status.isNewTransaction()) {
//事務連接釋放
doCleanupAfterCompletion(status.getTransaction());
}
//如果當前事務執行前有事務被掛起,這邊是設置一個Object的屬性,這也是事務傳播的一個處理
if (status.getSuspendedResources() != null) {
//恢復前一個掛起的事務
resume(status.getTransaction(), (SuspendedResourcesHolder) status.getSuspendedResources());
}
}