一、前言
文章目录:Spring源码深度解析:文章目录
在上篇中我们概述了Aop 实现的逻辑,但是由于篇幅原因,我们将一部分内容拆成了中篇和下篇内容。本篇即中篇,内容主要是讲述 在 Bean创建过程中Aop 挑选适用于当前Bean的增强Advisor。准备用于代理使用。由于篇幅连贯性,建议看完上篇后再来看本篇内容。
getAdvicesAndAdvisorsForBean
的实现在AbstractAdvisorAutoProxyCreator
类中。getAdvicesAndAdvisorsForBean
的作用是获取所有适用于当前Bean
的Advisors
。因为并不是所有的规则都适用于当前bean
,所有会有一个筛选的过程
这个方法的逻辑分为两步:
- 寻找所有的顾问(
Advisors
), 这个方法在AnnotationAwareAspectJAutoProxyCreator
中被重写了,为了可以的动态生成Advisor – findCandidateAdvisors
- 寻找所有顾问(
Advisors
) 中适用于当前 bean 的增强并应用 –findAdvisorsThatCanApply
下面我们来看详细代码:
AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean()
@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 主要逻辑还是在 findEligibleAdvisors 中完成。
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
//如果没有增强点则不需要代理。
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
AbstractAdvisorAutoProxyCreator#findEligibleAdvisors()
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 1. 寻找所有的增强
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 2. 寻找所有增强中适用于bean 的增强并应用
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
可以看到两个核心方法findCandidateAdvisors
和findAdvisorsThatCanApply
。下面我们一个一个来分析。
二、寻找所有Advisors - findCandidateAdvisors
前文讲过,Spring aop 注入的自动代理创建器是AnnotationAwareAspectJAutoProxyCreator
,所以AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
的代码如下:
AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors()
@Override
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
// 1. 这里是从BeanFactory 中找出来 所有 Advisor 类型的bean。即找到所有配置的Advisor。
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
// 2. buildAspectJAdvisors() 从代码中动态找到了需要的增强点
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
这里可以看到,AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
中通过
super.findCandidateAdvisors();
调用了父类的AbstractAdvisorAutoProxyCreator#findCandidateAdvisors()
的方法来获取Advisor
调用this.aspectJAdvisorsBuilder.buildAspectJAdvisors()
方法来获取Advisor
这两个方法都是为了获取 Advisor,区别在于
super.findCandidateAdvisors();
: 一般获取的都是通过直接注册的Advisors
。比如事务的顾问,直接通过@Bean
注入到Spring容器中。
this.aspectJAdvisorsBuilder.buildAspectJAdvisors()
: 主要获取我们通过注解方式动态注册的Advisors
。比如 在 Aop 中根据不同的表达式,每个@Pointcut
注解的切点不同,也就会对不同的Bean
起作用,并且对于每个@Pointcut
来说都有@Before
、@After
等不同的操作,那么每个@Pointcut
以及其对应的操作都会被封装成一个一个的Advisor
返回。下面会有详细解读。
1. super.findCandidateAdvisors();
super.findCandidateAdvisors();
说白了就是直接获取容器中的Advisor
类型的Bean
。
super.findCandidateAdvisors();
这里调用的实际上是AbstractAdvisorAutoProxyCreator
中的findCandidateAdvisors
方法。这一步最终会调用如下的findAdvisorBeans
方法。其作用根据注释也能明白。获取所有合格的 Advisor Bean
(合格并不代表适用当前bean),忽略了FactoryBean
和创建中的bean
。
BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans
public List<Advisor> findAdvisorBeans() {
// Determine list of advisor bean names, if not cached already.
// 从缓存中获取 advisorNames。因为每个Bean创建的时候都会进行一次获取,所以对增强的缓存是必须的
String[] advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the auto-proxy creator apply to them!
// 注释: 不要在这里初始化FactoryBeans:我们需要保留所有未初始化的常规bean,以使自动代理创建者对其应用!
// 个人理解是防止有的FactoryBean可能会被增强代理,而在这里初始化,则会没有办法进行代理
// 从Spring中获取Advisor类型的beanname。这里获取到的一般都是硬编码注入的Advisors
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
// 如果没有获取到Advisors,直接返回
if (advisorNames.length == 0) {
return new ArrayList<>();
}
// 到这一步必定有Advisors ,我们需要通过name来获取到bean的实例
List<Advisor> advisors = new ArrayList<>();
for (String name : advisorNames) {
// 当前Bean是否合格,这里调用的是AbstractAdvisorAutoProxyCreator#isEligibleAdvisorBean直接返回true,供子类扩展。
if (isEligibleBean(name)) {
// 如果name指向的bean正在创建中则跳过
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping currently created advisor '" + name + "'");
}
}
else {
try {
// 否则从容器中根据name和类型获取到Advisor实例,添加到advisors集合中
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
// 如果是异常时因为bean正在创建引起的在,则 continue
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
String bceBeanName = bce.getBeanName();
if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping advisor '" + name +
"' with dependency on currently created bean: " + ex.getMessage());
}
// Ignore: indicates a reference back to the bean we're trying to advise.
// We want to find advisors other than the currently created bean itself.
continue;
}
}
throw ex;
}
}
}
}
// 返回得到的合格的Advisor集合
return advisors;
}
2. this.aspectJAdvisorsBuilder.buildAspectJAdvisors()
this.aspectJAdvisorsBuilder.buildAspectJAdvisors()
的作用就是 在当前的bean工厂中查找带有AspectJ
注解的Aspect bean
,并封装成代表他们的Spring Aop Advisor
,注入到Spring
中。
基本的思路如下:
- 获取所有
beanName
,这一步所有在beanFactory
中注册的bean都会被提取出来 - 遍历所有的
beanName
, 找出声明AspectJ
注解的类,进行进一步处理 - 对标记为
AspectJ
注解的类进行Advisors
提取 - 将提取的结果保存到缓存中。
BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors()
public List<Advisor> buildAspectJAdvisors() {
// aspectBeanNames 中缓存了被@Aspect修饰的bean的name
List<String> aspectNames = this.aspectBeanNames;
// 如果为空表示尚未缓存,进行缓存解析。这里用了DLC方式来进行判断
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
// 1. 获取所有的beanName。从容器中获取所有的BeanName
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
// 遍历beanName, 找出对应的增强方法
for (String beanName : beanNames) {
// 不合法的bean略过,由子类定义规则,默认true
if (!isEligibleBean(beanName)) {
continue;
}
// 注释 :我们必须小心,不要急于实例化bean,因为在这种情况下,它们将由Spring容器缓存,但不会被编织。
// 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.
// 获取对应 bean 的类型
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
// 2. 如果bean被@AspectJ注解修饰 且不是Ajc编译, 则进一步处理
if (this.advisorFactory.isAspect(beanType)) {
// 添加到缓存中
aspectNames.add(beanName);
// 封装成AspectMetadata
AspectMetadata amd = new AspectMetadata(beanType, beanName);
// aspect 存在 SINGLETON、PERTHIS、PERTARGET、PERCFLOW、PERCFLOWBELOW、PERTYPEWITHIN模式。默认为SINGLETON 。暂不明白意义
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
// 3. 解析标记AspectJ注解中的增强方法,也就是被 @Before、@Around 等注解修饰的方法,并将其封装成 Advisor
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
// 保存 Advisor
advisors.addAll(classAdvisors);
}
else {
// Per target or per this.
// 如果当前Bean是单例,但是 Aspect 不是单例则抛出异常
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();
}
// 4. 将所有的增强方法保存到缓存中
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;
}
上面的方法一句话总结 : 获取容器中所有被@Aspect
修饰&&
不是Ajc
编译 的类,动态解析内容,封装成Advisor
保存到对应集合中。
下面我们来详细看看具体实现:
2.1、this.advisorFactory.getAdvisors(factory);
在上述代码中,最为复杂的就是增强器(Advisors
)获取,也就是this.advisorFactory.getAdvisors(factory);
这一步,
具体的实现是在ReflectiveAspectJAdvisorFactory#getAdvisors()
中。下面我们具体来看代码
ReflectiveAspectJAdvisorFactory#getAdvisors()
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// 获取标记为 AspectJ 的类
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
// 获取标记为 AspectJ 的名字
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
// 进行合法性验证
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
// 这里需要MetadataAwareAspectInstanceFactory,所以这里初始化了一次
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
// getAdvisorMethods(aspectClass)获取aspectClass中没有被@PointCut注解修饰的方法
for (Method method : getAdvisorMethods(aspectClass)) {
// 将方法封装成 Advisor 。如果找不到@PointCut 的信息,则会返回 null。下面详解
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// If it's a per target aspect, emit the dummy instantiating aspect.
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
// 如果寻找的增强器不为空而且有配置了增强延迟初始化,则需要在首位加入同步实例化增强器
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
// 获取 DeclaredParents 注解并处理。@DeclaredParents 注解可以实现指定某些代理类是某些接口的实现。
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
这里根据 切点信息来动态生成了增强器,也就是Advisor
。是根据AOP 的注解解析来的动态生成的。 可以看到,封装的关键的操作还是在getAdvisor
方法 中,下面我们来详细分析:
ReflectiveAspectJAdvisorFactory#getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,int declarationOrderInAspect, String aspectName)
// 筛选出合适的方法,并封装成 Advisor 。这里返回的都是 InstantiationModelAwarePointcutAdvisorImpl
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
// 又进行一次合法性校验
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 1. 切点信息的获取。这里如果没有被Aspect 系列注解(Pointcut、Around、Before等)修饰会返回null
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 如果获取不到相关信息直接返回null
if (expressionPointcut == null) {
return null;
}
// 2. 根据切点信息封装成增强器
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
可以看到在getAdvisor
方法中的关键两步: 切点信息的获取和根据切点信息封装成增强器。下面我们来继续分析
2.1.1. 切点信息的获取 - getPointcut
getPointcut
方法的实现很简单,就是判断方法上是否有AspectJ
系列的注解,有则封装。
@Nullable
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
// 获取方法上的注解,包括 Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// 到这里必然有 AspectJ系列的注解了
// 使用 AspectJExpressionPointcut 实例封装获取的信息
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
// 提取出的得到的注解中的表达式
// 如 @Pointcut("execution(* com.kingfish.aopdemo.controller.AopController.hello(String))") 中的 execution(* com.kingfish.aopdemo.controller.AopController.hello(String))
// 对于 @Before("pointCut()") 获取的则是 pointCut()
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
if (this.beanFactory != null) {
ajexp.setBeanFactory(this.beanFactory);
}
return ajexp;
}
其中AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
方法如下:
private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};
// 获取指定方法上的注解并使用 AspectJAnnotation 封装
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
if (foundAnnotation != null) {
return foundAnnotation;
}
}
return null;
}
2.1.2. 根据切点信息封装成增强器 - InstantiationModelAwarePointcutAdvisorImpl
在上面的代码中我们看到,ReflectiveAspectJAdvisorFactory#getAdvisor()
最终封装成了一个InstantiationModelAwarePointcutAdvisorImpl
返回。实际上,在 Aop 中所有的增强都由Advisor
的实现类InstantiationModelAwarePointcutAdvisorImpl
统一封装。我们来看看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);
}
}
...
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);
}
可以看到,InstantiationModelAwarePointcutAdvisorImpl
在封装过程中只是简单的将信息封装在类的实例中,所有的信息只是单纯的赋值。但是需要注意的是,在信息赋值结束后调用了instantiateAdvice(this.declaredPointcut);
方法,这个方法完成了对于增强器的处理。
因为不同的增强体现的逻辑是不同的,简单来说就是不同的切点信息的动作是不同的,比如@Before
和@After
注解的动作就不同,@Before
需要在切点方法前调用,@After
需要在切点方法后调用。这里根据不同的注解封装成了不同的Advice
,用以区分在适当的时候调用适当的方法。
而根据注解中的信息初始化对应的增强器就是在instantiateAdvice
中实现。而instantiateAdvice
中主要还是调用了this.aspectJAdvisorFactory.getAdvice
,因此我们来看this.aspectJAdvisorFactory.getAdvice
的代码:
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会根据不同的注解生成不同的增强器(通知)。比如AspectJAroundAdvice
、AspectJMethodBeforeAdvice
等,从而完成不同的注解所需的动作。
这里举个简单例子总结一下:
如下:
@Component
@Aspect
public class AopDemo {
@Pointcut("execution(* com.kingfish.aopdemo.controller.AopController.hello(String)) && args(msg)")
public void pointCut(String msg) {
System.out.println("AopDemo.pointCut : msg = " + msg);
}
@After("pointCut(msg)")
public void after(String msg) {
System.out.println("after msg = " + msg);
}
@Before("pointCut(msg)")
public void before(String msg) {
System.out.println("before msg = " + msg);
}
}
如上一个类,
- 容器启动后会加载硬编码注入的
Advisor
,加载结束后扫描@Aspect
注解类。 - 解析注解类里面的非
@PointCut
方法。即after、before
方法,对其注解进行信息进行解析,封装成InstantiationModelAwarePointcutAdvisorImpl
InstantiationModelAwarePointcutAdvisorImpl
中存在的PointCut
和Advice
两大属性,PointCut
代表切入点,Advice
代表增强的具体操作,根据不同的注解类型,加载不同的Advice
实现类。如下
- 最终会封装成两个
InstantiationModelAwarePointcutAdvisorImpl
,After
方法对应是AspectJAfterAdvice,Before
方法对应的是AspectJMethodBeforeAdvice,Pointcut
都是pointCut(msg)
三、筛选合适的Advisors - findAdvisorsThatCanApply
经历了第一步,也仅仅是将所有的顾问(Advisors),也就是增强器,全部查找出来。但是并非所有的Advisors 都适用于当前bean。所以这一步的目的是为了过滤出适合当前bean的增强器。
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
可以看到关键内容还是在AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
所以我们继续往下看。AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
的代码如下:
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
// 首先处理引介增强
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
// 引介增强已处理
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
// 对于普通bean 的处理
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
引介增强和普通的增强处理是不同的,所以需要分开处理。而通过上面的代码,我们可以看到关键逻辑在canApply
函数中,因此我们直接看这个函数。
public static boolean canApply(Advisor advisor, Class<?> targetClass) {
return canApply(advisor, targetClass, false);
}
....
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
// 基础篇曾介绍过,IntroductionAdvisor 和 PointcutAdvisor 的区别在于 PointcutAdvisor 的切入点更细。我们这里的Advisor都是PointcutAdvisor 类型
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
return true;
}
}
....
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
// 获取切点的方法匹配器
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
// 这里 introductionAwareMethodMatcher 的实现是 AspectJExpressionPointcut
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set<Class<?>> classes = new LinkedHashSet<>();
if (!Proxy.isProxyClass(targetClass)) {
classes.add(ClassUtils.getUserClass(targetClass));
}
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
for (Class<?> clazz : classes) {
// 获取当前bean的所有方法
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
// 在这里判断方法是否匹配
if (introductionAwareMethodMatcher != null ?
// 这里调用 AspectJExpressionPointcut#matches
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
注:introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)
实际上调用的是 AspectJExpressionPointcut#matches
,该方法中会通过AspectJExpressionPointcut#getTargetShadowMatch
调用AspectJExpressionPointcut#getShadowMatch
,在该方法中对表达式进行了校验,并返回了一个ShadowMatch
类,包含了校验后的结果信息。
从上面我们可以看到Pointcut
匹配的需要满足下面两个条件:
pc.getClassFilter().matches(targetClass)
返回true
pc.getMethodMatcher().matches(method, targetClass)
返回true
四、总结
getAdvicesAndAdvisorsForBean()
方法的作用就是筛选出适用于当前bean
的Advisor
。
简单来说就是两步
AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
挑选出所有的Advisor
。在 其中 通过 super.findCandidateAdvisors()
调用了AbstractAdvisorAutoProxyCreator#findCandidateAdvisors
来完成了对硬编码注入的Advisor
的获取解析返回。随后通过this.aspectJAdvisorsBuilder.buildAspectJAdvisors()
方式解析了 Aop 注解方式动态封装的Advisor
并保存。
findAdvisorsThatCanApply
通过Advisor
中的Pointcut
筛选出适合当前bean的Advisor
。
以上:内容部分参考
《Spring源码深度解析》
如有侵扰,联系删除。 内容仅用于自我记录学习使用。如有错误,欢迎指正