在源码笔记(一)中,我们留下了几个问题:
- 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中,左边红色的方框是调用栈,可以看到代码调用的顺序。
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
通过debug看到这个postProcessorNames变量的值如下图,红色框出来的是InfrastructureAdvisorAutoProxyCreator这个bean的名称。 阅读代码我们知道postProcessorNames来源于getBeanNamesForType,我们有必要跟踪进去,看看这个getBeanNamesForType做了什么。
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