Spring版本:
<version>5.2.1.RELEASE</version>
上一篇:23-Spring源码解析之AOP(2)——AnnotationAwareAspectJAutoProxyCreator类源码
上一篇我们讲完了与AOP
功能相关的四个问题中的两个问题:
- 【问题一】为什么在配置类中写了
@EnableAspectJAutoProxy
注解,Spring
就为我们在容器中注册了一个AnnotationAwareAspectJAutoProxyCreator
类的BeanDefinition
- 【问题二】
AnnotationAwareAspectJAutoProxyCreator
类是什么,它的类结构是什么样子的 - 【问题三】
BeanDefinition
只是Bean
的定义信息,什么时候创建AnnotationAwareAspectJAutoProxyCreator
类 - 【问题四】实现
AOP
功能与AnnotationAwareAspectJAutoProxyCreator
类有什么关系
本篇文章要讲解【问题四】,但是问题四包含的内容比较多,因此会拆成两篇文章讲解。
在分析源码之前,我们可以先尝试着想一下,AOP
功能的后续步骤若由我们实现,我们会怎么做?我觉得应该是这样的:
- 【步骤一】解析切面类(即被
@Aspect
注解标注的类),将切面类中的增强器提取出来,放到beanFactory
中管理 - 【步骤二】创建每个
Bean
的时候都拦截一下,判断beanFactory
中的增强器是不是用来增强当前Bean
的,若是则创建当前Bean
的代理,若不是就返回正常创建的普通Bean
。
实际上,Spring
就是根据以上两个步骤来做的AOP
功能。那么我们就开始去Spring
中找一下每一个步骤是在Bean
创建的什么时机做的吧。
一、解析@Aspect
获取增强器
根据之前看过的Spring
的源码,我们知道,注解解析都是通过Spring
中的BeanPostProcessor
完成的。那么我们先看一下该例子(例子在文章:22-Spring源码解析之AOP(1)——@EnableAspectJAutoProxy注解原理)中现在有的BeanPostProcessor
。
现在有6个BeanPostProcessor
,而只有AnnotationAwareAspectJAutoProxyCreator
类是与AOP
功能有关的,因此一定是该类解析了@Aspect
注解,那它在什么时候解析的呢?在上一篇文章中有提到AnnotationAwareAspectJAutoProxyCreator
类所属的BeanPostProcessor
类型。忘记了?不要紧,我再贴一遍。
AnnotationAwareAspectJAutoProxyCreator
类是属于InstantiationAwareBeanPostProcessor
类型的BeanPostProcessor
。那我们想一下之前讲过的Bean
生命周期中哪一步执行的是InstantiationAwareBeanPostProcessor
类型的BeanPostProcessor
。
是在实例化Bean
之前即createBean
方法调用的resolveBeforeInstantiation
方法中就执行了一次InstantiationAwareBeanPostProcessor
类型的BeanPostProcessor
。
我原以为是容器初始化阶段创建切面类(getBean(LogAspects)
)的时候执行的解析@Aspect
,但是经过一顿debug
发现事情并不是这样!而是在容器初始化阶段创建配置类的时候就开始解析@Aspect
了!这个地方一定要注意!
因此我们进入创建配置类时的createBean
调用resolveBeforeInstantiation
方法的地方。
我们进入resolveBeforeInstantiation
方法
在本节最开始,给出了当前beanFactory
中所有的BeanPostProcessor
。这里我只抽取与该功能有关的部分代码进行讲解,与该功能无关的方法暂时省略。所以我们直接遍历到当前BeanPostProcessor
为AnnotationAwareAspectJAutoProxyCreator
时执行postProcessBeforeInstantiation
方法。
这个时候由于上图中变量bp
的类型为AnnotationAwareAspectJAutoProxyCreator
,因此,这个时候调用的postProcessBeforeInstantiation
方法为AnnotationAwareAspectJAutoProxyCreator
父类AbstractAutoProxyCreator
类中的postProcessBeforeInstantiation
方法。
因为接下来的调用的方法是前面文章中没有分析过的方法,因此下面以代码的方式展示而非图片的方式展示。这样方便在代码中加入注释。
// 这个属性很重要,其键为beanFactory中Bean的beanNmae,值为该类是否是被@Aspect注解标注的类
private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<>(256);
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
// 因为是第一次进入,因此advisedBeans中还不包含任何的cacheKey
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
// -------------------shouldSkip 核心方法------------------------------------
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
判断当前Bean
是否是基础类型的Advice
、Pointcut
、Advisor
、AopInfrastructureBean
protected boolean isInfrastructureClass(Class<?> beanClass) {
boolean retVal = Advice.class.isAssignableFrom(beanClass) ||
Pointcut.class.isAssignableFrom(beanClass) ||
Advisor.class.isAssignableFrom(beanClass) ||
AopInfrastructureBean.class.isAssignableFrom(beanClass);
if (retVal && logger.isTraceEnabled()) {
logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]");
}
return retVal;
}
postProcessBeforeInstantiation
方法调用的shouldSkip
是解析@Aspect
获取增强器的核心方法,该方法是AspectJAwareAdvisorAutoProxyCreator
类中的方法。下面我们详细讲解shouldSkip
方法的功能。
二、AspectJAwareAdvisorAutoProxyCreator
类的shouldSkip
方法
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// --------------------------------------【功能一】--2.1 详细讲解------------------------------------------------------
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// --------------------------------------【功能二】--2.2 详细讲解------------------------------------------------------
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}
2.1 findCandidateAdvisors
方法
该方法的功能:获取容器中所有增强器。
findCandidateAdvisors
方法的实现是在AspectJAwareAdvisorAutoProxyCreator
类的子类AnnotationAwareAspectJAutoProxyCreator
中实现的,因此我们继续跟踪到AnnotationAwareAspectJAutoProxyCreator
类中的findCandidateAdvisors
方法。
protected List<Advisor> findCandidateAdvisors() {
// 当使用注解方式配置AOP的时候并不是丢弃了对XML配置的支持
// 在这里调用父类方法加载配置文件中的AOP声明(本例子使用的是AOP注解的方式,因此忽略这个方法的讲解)
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
在上篇文章中,创建时AnnotationAwareAspectJAutoProxyCreator
,给AspectJAwareAdvisorAutoProxyCreator
的aspectJAdvisorsBuilder
属性赋了值。因此当执行findCandidateAdvisors
时,这里的aspectJAdvisorsBuilder
不为null
。
我们继续跟踪到this.aspectJAdvisorsBuilder.buildAspectJAdvisors()
方法中。即BeanFactoryAspectJAdvisorsBuilder
类的buildAspectJAdvisors
方法。
public List