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<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
// --------------------------------------------【功能一】--------------------------------------------
// 获取beanFactory中的所有beanName
// 这一步骤中所有在beanFactory中注册的Bean都会被提取出来
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
// 遍历所有beanName,并找出声明@Aspect注解的类,进而找出对应的增强方法
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
// We must be careful not to instantiate beans eagerly as in this case they
// would be cached by the Spring container but would not have been weaved.
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
// --------------------------------------------【功能二】--------------------------------------------
// 找到声明AspectJ注解的类
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
// 用于存储被声明AspectJ注解的类 和 beanName
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
// --------------------------------------------【功能三】--核心 2.2 详细介绍------------------------------------------
// 对标记为AspectJ注解的类进行增强器的提取
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
// --------------------------------------------【功能四】--------------------------------------------
// 将提取的结果加入到缓存!!!很重要!!!
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
// Per target or per this.
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
// 若能执行到这一步,说明@AspectJ注解已经被解析过了,因此在这里直接从缓存中取出@AspectJ注解的类和对应的增强器即可。
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
- 【功能一】获取
beanFactory
中所有的Bean
我们可以看到,当前项目中beanFactory
里有15个Bean
,其中只有蓝色圈住的Bean
为我们项目中的类对应的Bean
,而只有beanNames[6]="logAspects"
为被标注了@Aspect
注解的类。
- 【功能二】找到声明
AspectJ
注解的类:this.advisorFactory.isAspect(beanType)
public boolean isAspect(Class<?> clazz) {
return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
}
private boolean hasAspectAnnotation(Class<?> clazz) {
return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
}
至此,我们完成了Advisor
的提取,在上面的步骤中最为重要也最为繁琐的就是【功能三】增强器的获取,而这一功能buildAspectJAdvisors
方法将它委托给了getAdvisors
方法去实现。
2.2 【功能三】this.advisorFactory.getAdvisors(factory)
我们看到调用this.advisorFactory.getAdvisors
的时候传递进来了一个factory
参数。先看一下传递进来的factory
是什么
从上幅图片可以看出factory
中包含beanFactory
、beanName
和被@Aspect
注解标注的类的信息。
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// 获取被`@Aspect`注解标注的类
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
// 获取被`@Aspect`注解标注的类对应的beanName
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
// 验证
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
// -------------------------------------------核 心-------------------------------------------
// 获取这个被`@Aspect`注解标注的类的所有方法
// -------------------------------------------【功能一】---2.2.1 详细介绍----------------------------------------
for (Method method : getAdvisorMethods(aspectClass)) {
// -------------------------------------------【功能二】---2.2.2 详细介绍----------------------------------------
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// -------------------------------------------【功能三】------------------------------------------
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
// 如果寻找的增强器不为空而且配置了增强延迟初始化那么需要在首位加入同步实例化增强器
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// -------------------------------------------【功能四】------------------------------------------
// 获取DeclaredParents注解
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
函数中首先完成了对增强器的获取,包括获取注解以及根据注解生成增强的步骤,然后考虑到在配置中可能回将增强配置成延迟初始化,那么需要在首位加入同步实例化增强器以保证增强使用之前的实例化,最后是对DeclaredParents
注解的获取。
下面我们主要介绍一下getAdvisors
方法中的【功能一】和【功能二】的具体实现。
2.2.1 getAdvisorMethods
该方法的功能:获取这个被@Aspect
注解标注的类的所有方法
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
final List<Method> methods = new ArrayList<>();
// ---------------------------核心-----------------------------
ReflectionUtils.doWithMethods(aspectClass, method -> {
// 声明为PointCut的方法不处理
if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
methods.add(method);
}
}, ReflectionUtils.USER_DECLARED_METHODS);
// 会对找到的所有方法进行排序
methods.sort(METHOD_COMPARATOR);
return methods;
}
public static void doWithMethods(Class<?> clazz, MethodCallback mc, @Nullable MethodFilter mf) {
// Keep backing up the inheritance hierarchy.
// 获取当前类的所有方法。
Method[] methods = getDeclaredMethods(clazz, false);
// 遍历每个方法
for (Method method : methods) {
if (mf != null && !mf.matches(method)) {
continue;
}
try {
mc.doWith(method);
}
catch (IllegalAccessException ex) {
throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
}
}
if (clazz.getSuperclass() != null && (mf != USER_DECLARED_METHODS || clazz.getSuperclass() != Object.class)) {
doWithMethods(clazz.getSuperclass(), mc, mf);
}
else if (clazz.isInterface()) {
for (Class<?> superIfc : clazz.getInterfaces()) {
doWithMethods(superIfc, mc, mf);
}
}
}
现在我们获取到了被@Aspect
注解标注的类的所有方法:5个。
接着我们看一下buildAspectJAdvisors
的功能二getAdvisor
。
2.2.2 getAdvisor
方法
该方法的功能:解析当前方法的切点注解 和 根据注解信息生成增强器。
我们在2.2.1节
看到被@Aspect
注解标注的类的所有方法:5个。但是由于我们不会去处理声明为PointCut
的方法,所以真正到达getAdvisor
方法进行处理的只有四个方法。如下所示:
我们以methods[0]
为例,讲解 getAdvisor
方法的实现过程。
先看一下传入getAdvisor
方法中的参数值。
啥也不说,直接上getAdvisor
源码
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
// -------------------------------------------【功能一】---核心---------------------------------------
// 切点信息获取
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
// -------------------------------------------【功能二】---核心---------------------------------------
// 根据切点信息生成增强器
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
- 【功能一】:切点信息获取
- 所谓获取切点信息就是指定注解的表达式信息的获取,如
@Before("pointCut()")
- 所谓获取切点信息就是指定注解的表达式信息的获取,如
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
// -------------------------------------------【功能一】---下面详细讲解-------------------------------------
// 获取方法上的注解
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// -------------------------------------------【功能二】------------------------------------------
// 使用AspectJExpressionPointcut示例封装获取的信息
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
// -------------------------------------------【功能三】------------------------------------------
// 提取得到的注解中的表达式
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
if (this.beanFactory != null) {
ajexp.setBeanFactory(this.beanFactory);
}
return ajexp;
}
我们来看一下他是如何通过findAspectJAnnotationOnMethod
方法获取方法上的注解的。
// 设置敏感的注解类
private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
Pointcut.class,
Around.class,
Before.class,
After.class,
AfterReturning.class,
AfterThrowing.class};
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
// 根据指定方法上的注解并使用AspectJAnnotation封装
AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
if (foundAnnotation != null) {
return foundAnnotation;
}
}
return null;
}
调用findAnnotation
方法获取指定方法上的注解,并将注解和方法利用AspectJAnnotation
封装起来
private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(
Method method, Class<A> toLookFor) {
A result = AnnotationUtils.findAnnotation(method, toLookFor);
if (result != null) {
return new AspectJAnnotation<>(result);
}
else {
return null;
}
}
- 【功能二】:根据切点信息生成增强器
- 所有的增强都是由
Advisor
的实现类InstantiationModelAwarePointcutAdvisorImpl
统一封装的
- 所有的增强都是由
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrder, String aspectName) {
// -------------------------------------------【功能一】--初始赋值----------------------------------------
this.declaredPointcut = declaredPointcut;
this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
this.methodName = aspectJAdviceMethod.getName();
this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
this.aspectJAdviceMethod = aspectJAdviceMethod;
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
this.aspectInstanceFactory = aspectInstanceFactory;
this.declarationOrder = declarationOrder;
this.aspectName = aspectName;
if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
// Static part of the pointcut is a lazy type.
Pointcut preInstantiationPointcut = Pointcuts.union(
aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
// Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
// If it's not a dynamic pointcut, it may be optimized out
// by the Spring AOP infrastructure after the first evaluation.
this.pointcut = new PerTargetInstantiationModelPointcut(
this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
this.lazy = true;
}
else {
// A singleton aspect.
this.pointcut = this.declaredPointcut;
this.lazy = false;
// -------------------------------------------【功能二】---核心---------------------------------------
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
}
在封装过程中只是简单地将信息封装在类的实例中,所有的信息单纯地赋值。 赋值的结果如下:
在实例InstantiationModelAwarePointcutAdvisorImpl
进行初始化过程中还完成了对于增强器的初始化。因为不同的增强器所体现的逻辑是不同的,比如:@Before("pointCut()")
和@After("pointCut()")
标签的不同就是增强器增强的位置不同,所以需要不同的增强器来完成不同的逻辑,而根据注解中的信息初始化对应得增强器就是在instantiateAdvice
函数中实现的。
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
Advice advice = this.aspectJAdvisorFactory.getAdvice(
this.aspectJAdviceMethod,
pointcut,
this.aspectInstanceFactory,
this.declarationOrder,
this.aspectName
);
return (advice != null ? advice : EMPTY_ADVICE);
}
下面调用的方法就是真正根据不同类型的注解来获得不同的增强器了。
public Advice getAdvice(Method candidateAdviceMethod,
AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrder,
String aspectName) {
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// If we get here, we know we have an AspectJ method.
// Check that it's an AspectJ-annotated class
if (!isAspect(candidateAspectClass)) {
throw new AopConfigException("Advice must be declared inside an aspect type: " +
"Offending method '" + candidateAdviceMethod + "' in class [" +
candidateAspectClass.getName() + "]");
}
if (logger.isDebugEnabled()) {
logger.debug("Found AspectJ method: " + candidateAdviceMethod);
}
AbstractAspectJAdvice springAdvice;
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter:
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing:
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
// Now to configure the advice...
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
从上面可以看出,Spring
会通过switch...case
语句来根据不同的注解生成不同的增强器。例如,@Befroe
对应case AtAfter
,因此返回的springAdvice = new AspectJMethodBeforeAdvice(....)
。
以上,我们完成了获取增强器的功能。现在我们回到2.1
findCandidateAdvisors方法
节。在执行完以上的步骤后,2.1
findCandidateAdvisors方法
中的advosor
的值变为:
至此,我们完成了shouldSkip()
方法中调用的findCandidateAdvisors
的分析。现在,我们回到二、AspectJAwareAdvisorAutoProxyCreator类的shouldSkip方法
地方。这个shouldSkip
只有两个功能。那么我们来看看第二个功能:
当前的类是配置类mainConfig_AOP
,返回的candidateAdvisors
中的advisor
的getAspectName
值都是logAsoects
,因此这里的for
循环不会return true
。而是会执行当前类的父类的shouldSkip
方法。而当前类的父类的shouldSkip
方法始终返回false
。
至此,我们已经分析完了shouldSkip
。我们回到调用shouldSkip
的地方,即一、解析@Aspect
获取增强器节,由于本文有点长,所以我把一节中调用shouldSkip
的地方的代码粘贴过来:
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
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;
}
通过以上分析我们知道if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName))
的结果是false
。因此往下执行,执行到最后返回null
。
三、总结
本篇文章的内容有些庞杂,本篇文章主要做的工作就是:解析@Aspect
获取增强器,下面对解析过程做一个小结
记住:我们在解析@Aspect
获取增强器的时候,将解析的结果放到了缓存中,我再把加入到缓存的地方贴出来一下:
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
就是将解析好的被标注@Aspect
注解的类和对应的增强器放到了advisorsCache
中。在下一节我们会用到这个advisorsCache
。
至此,注解@Aspect
的解析和增强器的获取就讲解完了,我们下一篇讲解:切面类和被切面类切入的类在创建Bean
的时候AnnotationAwareAspectJAutoProxyCreator
所作的事情。