Spring Boot Transactional註解源碼閱讀筆記(二)

  在源碼筆記(一)中,咱們留下了幾個問題:java

  • Spring Boot是怎麼掃描到咱們的bean裏面有 Transactional 這個註解,而且把 InfrastructureAdvisorAutoProxyCreator 這個 BeanPostProcessor註冊到bean的信息裏面去的。
  • Spring Boot生成的cglib proxy在調用帶有 Transactional 註解的方法前到底作了什麼,它插入了哪些代碼,這些代碼是什麼含義。

  今天這篇文章將要談一談第一個問題:Spring Boot是怎麼掃描到咱們的bean裏面有 Transactional 這個註解,而且把 InfrastructureAdvisorAutoProxyCreator 這個 BeanPostProcessor註冊到bean的信息裏面去的spring

1. 定位代碼位置

  在筆記一里面咱們提到,在生成cglib proxy的過程當中,會在 AbstractAutowireCapableBeanFactory裏面調用 getBeanPostProcessors方法,這個方法返回的是一個叫beanPostProcessors的成員變量,經過搜索咱們發現,AbstractAutowireCapableBeanFactory 的父類 AbstractBeanFactory有一個addBeanPostProcessor的方法,這個方法會把咱們須要跟蹤的InfrastructureAdvisorAutoProxyCreator加到beanPostProcessors這個list中。經過斷點,咱們能夠看到如今已經找到了InfrastructureAdvisorAutoProxyCreator被加到list中,左邊紅色的方框是調用棧,能夠看到代碼調用的順序。 post

  經過上面的調用棧,能夠找到 PostProcessorRegistrationDelegate裏面有一個這樣的方法: registerBeanPostProcessors(ConfigurableListableBeanFactory,AbstractApplicationContext),方法裏面有這樣一段代碼:

String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
複製代碼

  經過debug看到這個postProcessorNames變量的值以下圖,紅色框出來的是InfrastructureAdvisorAutoProxyCreator這個bean的名稱。 閱讀代碼咱們知道postProcessorNames來源於getBeanNamesForType,咱們有必要跟蹤進去,看看這個getBeanNamesForType作了什麼。this

  進入到 getBeanNamesForType方法以後,咱們很快就發如今 DefaultListableBeanFactory裏面有一個 beanDefinitionNames的變量,從它的值裏面咱們能夠找到 internalAutoProxyCreator,咱們須要知道這個beanName是何時被加到 beanDefinitionNames裏面去的。在 DefaultListableBeanFactory裏面有一個 registerBeanDefinition的方法,咱們打上斷點,加上條件命中,進行觀察。左側是調用棧,有了這個咱們就能很方便的知道這個 internalAutoProxyCreator是怎麼來的。

  跟着調用棧看了一會,發現這些地方只是把解析 Transactional註解的類註冊到了 DefaultListableBeanFactory裏面,並無涉及到如何的解析註解,彷佛方向錯了。

2. 起色

  回到InfrastructureAdvisorAutoProxyCreator,咱們看看是否是它在處理bean的時候解析了Transactional註解。它的父類AbstractAutoProxyCreator的方法wrapIfNecessary中有如下一段代碼:spa

Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
複製代碼

  跳轉到AbstractAdvisorAutoProxyCreator的方法getAdvicesAndAdvisorsForBean,其中有這樣一段代碼:debug

List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
複製代碼

  跳轉到findEligibleAdvisors,其中有一段代碼:code

List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
複製代碼

  進到findAdvisorsThatCanApply方法,看到如下代碼:cdn

return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
複製代碼

  跟着程序執行的順序,最後走到了AopUtils的方法canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions),方法中有一段代碼blog

if ((introductionAwareMethodMatcher != null &&
						introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
						methodMatcher.matches(method, targetClass)) {
					return true;
}
複製代碼

進到methodMatcher.matches,看到下面這段代碼:ci

return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
複製代碼

  接着進入tas.getTransactionAttribute最終會來到類AbstractFallbackTransactionAttributeSource,在它的getTransactionAttribute方法中,咱們重點看一下下面這行代碼:

TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
複製代碼

  進到方法的裏面,執行到下面代碼:

TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
複製代碼

  findTransactionAttribute 方法由AbstractFallbackTransactionAttributeSource的子類AnnotationTransactionAttributeSource 實現,繼續跟蹤到了determineTransactionAttribute方法,能夠看到這個方法的代碼是這樣的:

if (ae.getAnnotations().length > 0) {
		for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
			TransactionAttribute attr = annotationParser.parseTransactionAnnotation(ae);
			if (attr != null) {
				return attr;
			}
		}
	}
return null;
複製代碼

  終於開始判斷方法上面註解的個數,這可能意味着咱們快要找到spring是在哪兒解析Transactional註解了。咱們接着往下執行,進到了SpringTransactionAnnotationParser類中,它的方法parseTransactionAnnotation有這麼一段代碼:

AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ae, Transactional.class);
複製代碼

  這一段就是用來解析咱們transactional註解的,至此咱們已經找到了spring是在什麼地方解析bean裏面的transactional註解的。

3.總結

  本期解決了筆記(一)留下的兩個問題中一個,接下來會花一些時間來跟蹤一下cglib proxy對帶有Transactional註解的方法作了什麼。

插播一段廣告,阿里巴巴長期招聘,有須要內推的朋友能夠加脈脈私聊,或者簡歷發到linlan.zcj@alibaba-inc.com

相關文章
相關標籤/搜索