在源码笔记(一)中,我们留下了几个问题:
- 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