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

相关文章
相关标签/搜索