Spring Boot Transactional注解源码阅读笔记(二)

  在源码笔记(一)中,我们留下了几个问题:

  • Spring Boot是怎么扫描到我们的bean里面有 Transactional 这个注解,并且把 InfrastructureAdvisorAutoProxyCreator 这个 BeanPostProcessor注册到bean的信息里面去的。
  • Spring Boot生成的cglib proxy在调用带有 Transactional 注解的方法前到底做了什么,它插入了哪些代码,这些代码是什么含义。

  今天这篇文章将要谈一谈第一个问题:Spring Boot是怎么扫描到我们的bean里面有 Transactional 这个注解,并且把 InfrastructureAdvisorAutoProxyCreator 这个 BeanPostProcessor注册到bean的信息里面去的

1. 定位代码位置

  在笔记一里面我们提到,在生成cglib proxy的过程中,会在 AbstractAutowireCapableBeanFactory里面调用 getBeanPostProcessors方法,这个方法返回的是一个叫beanPostProcessors的成员变量,通过搜索我们发现,AbstractAutowireCapableBeanFactory 的父类 AbstractBeanFactory有一个addBeanPostProcessor的方法,这个方法会把我们需要跟踪的InfrastructureAdvisorAutoProxyCreator加到beanPostProcessors这个list中。通过断点,我们可以看到现在已经找到了InfrastructureAdvisorAutoProxyCreator被加到list中,左边红色的方框是调用栈,可以看到代码调用的顺序。

  通过上面的调用栈,可以找到 PostProcessorRegistrationDelegate里面有一个这样的方法: registerBeanPostProcessors(ConfigurableListableBeanFactory,AbstractApplicationContext),方法里面有这样一段代码:

String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
复制代码

  通过debug看到这个postProcessorNames变量的值如下图,红色框出来的是InfrastructureAdvisorAutoProxyCreator这个bean的名称。 阅读代码我们知道postProcessorNames来源于getBeanNamesForType,我们有必要跟踪进去,看看这个getBeanNamesForType做了什么。

  进入到 getBeanNamesForType方法之后,我们很快就发现在 DefaultListableBeanFactory里面有一个 beanDefinitionNames的变量,从它的值里面我们可以找到 internalAutoProxyCreator,我们需要知道这个beanName是什么时候被加到 beanDefinitionNames里面去的。在 DefaultListableBeanFactory里面有一个 registerBeanDefinition的方法,我们打上断点,加上条件命中,进行观察。左侧是调用栈,有了这个我们就能很方便的知道这个 internalAutoProxyCreator是怎么来的。

  跟着调用栈看了一会,发现这些地方只是把解析 Transactional注解的类注册到了 DefaultListableBeanFactory里面,并没有涉及到如何的解析注解,似乎方向错了。

2. 转机

  回到InfrastructureAdvisorAutoProxyCreator,我们看看是不是它在处理bean的时候解析了Transactional注解。它的父类AbstractAutoProxyCreator的方法wrapIfNecessary中有以下一段代码:

Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
复制代码

  跳转到AbstractAdvisorAutoProxyCreator的方法getAdvicesAndAdvisorsForBean,其中有这样一段代码:

List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
复制代码

  跳转到findEligibleAdvisors,其中有一段代码:

List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
复制代码

  进到findAdvisorsThatCanApply方法,看到以下代码:

return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
复制代码

  跟着程序执行的顺序,最后走到了AopUtils的方法canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions),方法中有一段代码

if ((introductionAwareMethodMatcher != null &&
						introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
						methodMatcher.matches(method, targetClass)) {
					return true;
}
复制代码

进到methodMatcher.matches,看到下面这段代码:

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值