由于md文档部分hugo插件语法不兼容,建议访问作者网站查阅文章:wlizhi.cc

spring源码系列文章,示例代码的中文注释,均是 copy 自 https://gitee.com/wlizhi/spring-framework 。

链接中源码是作者从 github 下载,并以自身理解对核心流程及主要节点做了详细的中文注释。


1 主流程

AOP是通过 BeanPostProcessor.postProcessAfterInitialization() 实现的,来到 doCreateBean() -> initializeBean(),在初始化方法执行完成后,会调用 applyBeanPostProcessorsAfterInitialization(),这里循环调用了所有 BeanPostProcessor 的 postProcessAfterInitialization(),AOP 的入口就在其中的一个实现类,也是 AbstractAutoProxyCreator 的子类实现。

在生成代理之前,spring 会根据扫描规则,搜集容器中注册的所有 Advisor 实例、并搜集通知方法(@Aspect 注解的类中的@Before、@Around等注解标识的方法),将其封装成 Advisor。然后逐个与当前 bean 实例匹配,匹配到的放入一个集合中。

来到入口方法 postProcessAfterInitialization(),源码如下:

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupportimplements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {@Overridepublic Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) {// 如果是FactoryBean,cacheKey是 &+beanName拼接而成,如果benaName为空,则是类名称。Object cacheKey = getCacheKey(bean.getClass(), beanName);if (!this.earlyProxyReferences.contains(cacheKey)) {// TODO 必要时包装给定的bean,即是否有资格被代理。return wrapIfNecessary(bean, beanName, cacheKey);}}return bean;}
}

如果需要生成代理(自定义切面、事务等),会调用 wrapIfNecessary()。

wrapIfNecessary() 是这么定义的:
{{< highlight java “linenos=table,hl_lines=7 11 12,linenostart=1” >}}
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 省略无关代码…
// TODO 重点:如果有需要增强,就创建代理对象,这里会循环此类中所有的方法,如果有增强匹配到类中的方法,就会将增强对象封装到list中。
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// TODO 重点:创建代理对象
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
}
{{< /highlight >}}
{{< admonition title=“注意” open=true >}}
从源码中可以看到,关键点有两个:

  1. 搜集容器中所有匹配当前bean的通知方法。(如果当前bean中有方法被 pointCut 匹配到,就满足条件,将对应的通知方法封装到数组中返回)
  2. 根据匹配的通知方法列表,创建代理对象。(这里会将已排序的通知方法列表,生成一个执行链,缓存起来,当代理对象方法被调用时调用回调方法的时候,会火炬传递式的调用执行链中的通知方法。JDK动态代理和cgliib封装方式大同小异,通知方法都在回调函数所在的类中作为一个成员缓存。)
    {{< /admonition >}}

2 搜集封装Advisor

2.1 搜集流程

getAdvicesAndAdvisorsForBean() 会调用到 findEligibleAdvisors()。来到这个方法:

public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {//查找到所有的增强方法,封装成Advisor对象。这里查找了两种增强,一种是实现了Advisor的实例,一种是带有@Aspect注解的bean实例中定义的增强方法。List<Advisor> candidateAdvisors = findCandidateAdvisors();// 根据每个增强中的切点表达式,进行匹配,筛选出合适的增强实例列表。List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);extendAdvisors(eligibleAdvisors);// 对增强方法进行排序,可以不看。if (!eligibleAdvisors.isEmpty()) {eligibleAdvisors = sortAdvisors(eligibleAdvisors);}return eligibleAdvisors;}
}

这里分为了两步:

  1. 收集到容器中所有的增强方法、封装成 Advisor(如果本身就是 Advisor,直接返回)。
  2. 从这所有的 Advisor 中筛选出匹配当前 bean 的 Advisor 列表。

从 AbstractAutoProxyCreator的注册 已经知道,这里使用的是 AnnotationAwareAspectJAutoProxyCreator。

进入 findCandidateAdvisors():

public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {@Overrideprotected List<Advisor> findCandidateAdvisors() {// TODO 从父类中获取,这里获取了所有注入到容器中的Advisor类型的实例。事务的增强实例,就是在这里查找的。// Add all the Spring advisors found according to superclass rules.List<Advisor> advisors = super.findCandidateAdvisors();// Build Advisors for all AspectJ aspects in the bean factory.if (this.aspectJAdvisorsBuilder != null) {// TODO 将beanFactory中缓存的所有bean实例,依次校验是否带有@Aspect注解,如果有,将其中的//  增强方法、切点表达式等信息,封装成Advisor。advisors变量最终存储了所有切面的增强方法封装。advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());}return advisors;}
}

看上面代码,首先,从父类中查找 Advisor列表,然后调用 buildAspectJAdvisors(),将两者结果聚合到一个列表。


先看父类中的代码:

public class BeanFactoryAdvisorRetrievalHelper {public List<Advisor> findAdvisorBeans() {String[] advisorNames = this.cachedAdvisorBeanNames;if (advisorNames == null) {// 从容器中获取所有的Advisor类型的额bean名称advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Advisor.class, true, false);this.cachedAdvisorBeanNames = advisorNames;}// 省略非关键代码...List<Advisor> advisors = new ArrayList<>();for (String name : advisorNames) {if (isEligibleBean(name)) {// 从beanFactory中获取所有的Advisor类型的实例,事务支持TransactionAttributeSourceAdvisor实际上就是一个Advisor。advisors.add(this.beanFactory.getBean(name, Advisor.class));}}return advisors;}
}

这里搜集了容器中所有 Advisor 类型的 beanName,并将其缓存。然后调用 getBean(),将其实例化。(事务的 Advisor 其实就是在这里创建的


再看子类中的代码 buildAspectJAdvisors():

public class BeanFactoryAspectJAdvisorsBuilder {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<>();String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);for (String beanName : beanNames) {// 如果不是合格的beanName,则跳过if (!isEligibleBean(beanName)) {continue;}Class<?> beanType = this.beanFactory.getType(beanName);if (beanType == null) {continue;}// 判断当前beanType是否是一个切面。判断类上是否有@Aspectif (this.advisorFactory.isAspect(beanType)) {aspectNames.add(beanName);// 创建切面元数据实例,里面封装了切面类型,切点表达式等信息。AspectMetadata amd = new AspectMetadata(beanType, beanName);// 默认就是SINGLETONif (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {MetadataAwareAspectInstanceFactory factory =new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);// TODO 获取Advisor,这里封装了当前Aspect类中的增强方法,每个增强方法都会封装成一个Advisor。List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);if (this.beanFactory.isSingleton(beanName)) {// 将Advisor放入到缓存中,从上面的流程获取时,会先走缓存,缓存中有,就不会遍历查找了。// 这个代码块使用了双检索,这块代码在spring容器启动时,只会执行一次。this.advisorsCache.put(beanName, classAdvisors);}else {this.aspectFactoryCache.put(beanName, factory);}advisors.addAll(classAdvisors);}// 省略...}}this.aspectBeanNames = aspectNames;return advisors;}}}// 省略...// 根据切面名称,从缓存中获取到指定的增强实例,封装起来返回。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;}
}

上面代码略长、主要看带有注释的地方。代码主要流程:

  1. 获取到容器中所有的 beanName,遍历。
  2. 挨个判断,如果当前类上有 @Aspect,则解析这个类中通知方法及切入点表达式等信息。
  3. 调用 getAdvisors() 获取类中所有的通知方法,将其封装成 Advisor,作为一个列表返回。
  4. 放入缓存,下次进入就不会再遍历所有 beanNames 计算,而是从缓存中获取。

重点就在 getAdvisors(),在此之前,先来看看 isAspect():

public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFactory {public boolean isAspect(Class<?> clazz) {// 这里判断类型是否包含@Aspectreturn (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));}private boolean hasAspectAnnotation(Class<?> clazz) {return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);}
}

isAspect() 中的逻辑非常简单,判断当前类中是否有 @Aspect 注解(第二个条件可以忽略,判断类中是否有字段以 ajc$ 一个特殊的标识开头的)。

来到 getAdvisors():

public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable {public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {// 获取切面类型,切面名称Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();validate(aspectClass);MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);List<Advisor> advisors = new ArrayList<>();// 获取增强方法,并按照方法名称排序。for (Method method : getAdvisorMethods(aspectClass)) {// TODO 将增强方法封装成Advisor,并添加到advisors变量中,最终会将这个变量返回。Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);if (advisor != null) {advisors.add(advisor);}}// 引介,基本用不到,这里代码省略...return advisors;}
}

注意:这个方法是在一个循环中调入进来的,aspectInstanceFactory 中封装了当前遍历到的 beanName 以及 beanFactory 的信息。

  1. getAdvisorMethods(),获取到所有非切点表达式的方法,也就是不带 @PointCut 注解的方法。
  2. 遍历这些方法,getAdvisor() 将方法封装成 Advisor。

getAdvisorMethods() 源码如下:

public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable {private List<Method> getAdvisorMethods(Class<?> aspectClass) {final List<Method> methods = new ArrayList<>();ReflectionUtils.doWithMethods(aspectClass, method -> {// Exclude pointcutsif (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {methods.add(method);}});// 先按照注解排序、如果是相同的注解,就按照方法名称排序。methods.sort(METHOD_COMPARATOR);return methods;}
}

排序的代码有一点绕,嵌套的 lambda 表达式,是这么定义的(可以不看,实际业务中一般一个切面类只定义一个通知方法):

public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable {private static final Comparator<Method> METHOD_COMPARATOR;static {Comparator<Method> adviceKindComparator = new ConvertingComparator<>(new InstanceComparator<>(Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),(Converter<Method, Annotation>) method -> {AspectJAnnotation<?> annotation =AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);return (annotation != null ? annotation.getAnnotation() : null);});// 先按照注解排序、如果是相同的注解,就按照方法名称排序。Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);METHOD_COMPARATOR = adviceKindComparator.thenComparing(methodNameComparator);}
}

先使用 methodNameComparator 进行排序,如果排序结果相等,再使用 methodNameComparator 进行排序。每个比较器排序前都会使用 Converter<S, T> 转换其类型。

调用 getAdvisor():

public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable {public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,int declarationOrderInAspect, String aspectName) {validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());// 将当前方法、类型作为参数。获取PointCut对象,最重要的是从注解中获取表达式AspectJExpressionPointcut expressionPointcut = getPointcut(candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());if (expressionPointcut == null) {return null;}// 这里封装了切点表达式、切面类型、增强方法等信息。它是Advisor的一个实现类,最终会加入到代理实例的执行链中。return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,this, aspectInstanceFactory, declarationOrderInAspect, aspectName);}
}
  1. 获取到通知方法的 PointCut() 对象,如果有方法没有切点表达式,直接返回null,这种情况会被忽略,不被加入到 Advisor 列表中。
  2. 创建 Advisor 对象,封装切点表达式、通知方法等必要信息。

2.2 PointCut的获取

关于如何获取 PointCut 的,源码如下:

public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable {private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {// 找到切面相关注解,并把注解信息解析出来,包装成AspectJAnnotationAspectJAnnotation<?> 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():

public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFactory {/** 这里定义了切面中支持的注解,前置、后置、环绕等通知类型 */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) {// 循环去找注解,并把注解信息解析出来,包装成AspectJAnnotationAspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);if (foundAnnotation != null) {return foundAnnotation;}}return null;}// 步骤二private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) {// 找的规则就是找注解的父注解,递归的方式去找,直到找到目标注解为止A result = AnnotationUtils.findAnnotation(method, toLookFor);if (result != null) {// 把注解里面对的信息解析出来,然后包装成AspectJAnnotation对象return new AspectJAnnotation<>(result);}else {return null;}}
}

从上面代码可以看到,ASPECTJ_ANNOTATION_CLASSES数组常量中,预定义了支持切点表达式的注解。如果能在当前方法上找到任何一种,就将这个切点信息封装成 AspectJAnnotation。

2.3 Advisor的初始化

这里还有一个重点,new InstantiationModelAwarePointcutAdvisorImpl 中的初始化过程。

构造函数源码如下:
{{< highlight java “linenos=table,hl_lines=18,linenostart=1” >}}
final class InstantiationModelAwarePointcutAdvisorImpl
implements InstantiationModelAwarePointcutAdvisor, AspectJPrecedenceInformation, Serializable {

public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
// 切点、切面名称、通知方法名称、等等一系列信息的封装
this.declaredPointcut = declaredPointcut;
// 省略…

 if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {// 省略...}else {// A singleton aspect.this.pointcut = this.declaredPointcut;this.lazy = false;// TODO 重点,实例化的过程,这里封装了具体的Advicethis.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);}
}

}
{{< /highlight >}}
重点方法是 instantiateAdvice(),这里完成了 Advice 的创建。

继续向下跟踪代码:

final class InstantiationModelAwarePointcutAdvisorImplimplements InstantiationModelAwarePointcutAdvisor, AspectJPrecedenceInformation, Serializable {private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {// TODO 重点getAdviceAdvice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,this.aspectInstanceFactory, this.declarationOrder, this.aspectName);return (advice != null ? advice : EMPTY_ADVICE);}
}

来到 getAdvice():

public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable {public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {// 获取切面类Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();validate(candidateAspectClass);// 查找切点表达式、五种通知增强注解。@Before等五种。AspectJAnnotation<?> aspectJAnnotation =AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);if (aspectJAnnotation == null) {return null;}// 省略部分代码...AbstractAspectJAdvice springAdvice;// TODO 执行判断,针对不同类型的通知,封装不同类型的Advice//  这几个Advice的实现类要记一下。主要以是否实现MethodInterceptor来区分,有的实现了,有的没有。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);}// 省略...return springAdvice;}
}

{{< admonition tip= title=“注意” open=true >}}
上面代码中,AspectJMethodBeforeAdvice 等几个Advice的实现要看一下,这里五个 Advice 实现,部分实现了MethodInterceptor。
实现了MethodInterceptor的:

  1. AspectJAroundAdvice
  2. AspectJAfterAdvice
  3. AspectJAfterThrowingAdvice

未实现MethodInterceptor的 --> 生成执行链时依赖的适配器:

  1. AspectJMethodBeforeAdvice --> MethodBeforeAdviceAdapter
  2. AspectJAfterReturningAdvice --> AfterReturningAdviceAdapter

另外还有一个未用到的Advice,也没有实现MethodInterceptor
ThrowsAdvice --> ThrowsAdviceAdapter

在生成搭理对象后,真正执行代理方法生成执行链的时候,实现了MethodInterceptor和未实现前者的,调用逻辑上有些差别。

实现了MethodInterceptor的,会直接加入到执行链,未实现的,会通过对应的适配器,调用 getInterceptor() 来获取 MethodInterceptor,然后将 MethodInterceptor 加入执行链。(这些是后话)
{{< /admonition >}}

3 筛选出匹配的Advisor

在获取到容器中所有的通知方法封装成的 Advisor 后,会调用 findAdvisorsThatCanApply(),将 beanName 放入到一个 ThreadLocal 类型的变量中,然后调用 findAdvisorsThatCanApply() 的重载方法。调用完毕之后,会将 ThreadLocal 变量中的 beanName置空。

findAdvisorsThatCanApply() 重载方法源码如下:

public abstract class AopUtils {public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {if (candidateAdvisors.isEmpty()) {return candidateAdvisors;}List<Advisor> eligibleAdvisors = new ArrayList<>();// 先处理IntroductionAdvisor类型的增强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 processedcontinue;}// 我们自定义的切面,就会走到这里,使用已经封装的PointcutAdvisor,根据切点表达式进行匹配,具体的匹配过程,不用看。if (canApply(candidate, clazz, hasIntroductions)) {eligibleAdvisors.add(candidate);}}return eligibleAdvisors;}
}

调用 canApply(),这里进行了切点表达式与方法的匹配,如果匹配成功,将 Advisor 放入到集合中,否则就跳过。

当将所有的 Advisor 遍历完毕,最终匹配成功的 Advisor 会被筛选出来,放入到一个新的集合中,最终生成的执行链中的通知方法,就来自筛选后的 Advisor 集合(这个集合在创建代理前还有一次新增操作)。

看 canApply(),这里进行了匹配:

public abstract class AopUtils {// 步骤一public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {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) {// 省略...// 这里做了切入点表达式的匹配,匹配通过的返回true,具体的匹配过程不用看,不是重点。for (Class<?> clazz : classes) {Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);for (Method method : methods) {if (introductionAwareMethodMatcher != null ?introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :methodMatcher.matches(method, targetClass)) {return true;}}}return false;}
}

从上面代码可以看到,PointcutAdvisor 类型的,最终会遍历类中所有的方法,根据切点表达式,进行一一匹配,如果匹配成功,返回true,否则返回false。

4 搜集容器中所有的Advisor的流程

  1. 父类调用流程:
    {{< mermaid >}}
    graph LR;
    B(findCandidateAdvisors) -->|One| C(super.findCandidateAdvisors)
    C --> CA{findAdvisorBeans}
    CA -->|One| CAA(beanNamesForTypeIncludingAncestors)
    CA -->|Two| CAB(beanFactory.getBean)
    {{< /mermaid >}}
  2. 子类调用流程:
    {{< mermaid >}}
    graph TB;
    B(findCandidateAdvisors) -->|Two| D(buildAspectJAdvisors)
    D -->|ForEach| E(beanNames)
    E --> F(isAspect) -->|true| G{getAdvisors}
    G -->|One| GA(getAdvisorMethods)
    GA --> GAA1(doWithMethods) --> GAA2(“getAnnotation(method, Pointcut.class)”)
    G -->|Two| GB(getAdvisor)
    GB --> GBA(getPointcut)
    GBA --> GBAA(findAspectJAnnotationOnMethod) -->|forEach| GBAA1(ASPECTJ_ANNOTATION_CLASSES)
    GBAA1 --> GBAA2(findAnnotation) --> GBAA3(“new AspectJAnnotation<>(result)”)
    {{< /mermaid >}}

10 AOP Advisor的封装与搜集相关推荐

  1. spring AOP中 aop:advisor 与 aop:aspect 的区别

    在开发过程中,不少有Spring Aop的使用, 在面向切面编程时,我们会使用< aop:aspect>: 在进行事务管理时,我们会使用< aop:advisor>. 那么,对 ...

  2. 关于spring aop Advisor排序问题

    关于spring aop Advisor排序问题 当我们使用多个Advisor的时候有时候需要排序,这时候可以用注解org.springframework.core.annotation.Order或 ...

  3. spring Aop中aop:advisor 与 aop:aspect的区别

    在spring的配置中,会用到这两个标签.那么他们的区别是什么呢? <bean id="testAdvice" class="com.myspring.app.ao ...

  4. redis返回的结果是null_Spring AOP 用注解封装 redis 缓存

    前言 面试时问到用没用过 AOP,很多回答都是用 AOP 做过日志统一处理. 给人感觉就是没做过啊 今天介绍一个用注解封装 redis 缓存的 AOP 实战 redis 缓存加速的基本逻辑 用 red ...

  5. 在Debian 7/Ubuntu 13.10 上使用隧道封装SSH连接

    隧道 被设计用于远端客户端和本地(可通过inetd启动)或远端服务器间的SSL加密封装.它可以用于为inetd进程增加SSL功能,像POP2(译注:厄,POP2这个服务还有人用么?),POP3和IMA ...

  6. [10] AOP的注解配置

    1.关于配置文件 首先在因为要使用到扫描功能,所以xml的头文件中除了引入bean和aop之外,还要引入context才行: <?xml version="1.0" enco ...

  7. Java讲课笔记10:类的封装

    文章目录 零.本讲学习目标 1.掌握类的封装 2.学会使用方法的重载 3.学会方法的递归 一.类的封装 1.为什么需要封装 (1)案例演示 (2)案例分析 (3)解决方案 2.如何实现封装 (1)封装 ...

  8. c语言 Mupdf 1.10版本常用功能封装

    因近期公司项目要做一些pdf文件处理,在比较多个开源库后,感觉mupdf还不错,就选择了它. https://mupdf.com/downloads/archive/mupdf-1.0-source. ...

  9. aopaspect区别_spring 中的aop:advisor和aop:aspect有什么区别?

    在xml中 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www ...

最新文章

  1. php 遍历所有的文件
  2. Ingress 继任者 Gateway API 使用
  3. 13岁女孩因发布JavaScript无限循环代码被捕
  4. 手机直播系统源码搭建说明
  5. Java程序员从笨鸟到菜鸟之(七十八)细谈Spring(七)spring之JDBC访问数据库及配置详解
  6. 火狐浏览器插件HTTPFOX抓传输数据
  7. PWN-PRACTICE-BUUCTF-23
  8. Leetcode-3 无重复字符的最长子串【c语言】
  9. LeetCode 413. Arithmetic Slices
  10. 数据不够,怎么训练数据集?别怕,有TA
  11. php 魔术方法使用说明详细
  12. oracle userenv(sid),ORACLE USERENV函数
  13. jmeter使用中的问题
  14. matlab细胞数组类型建立及操作
  15. 基于VS快速排序的单元测试
  16. sqlServer数据库自动备份
  17. 反恐精英代码_知名网游源代码泄漏 ,外挂潮将来?
  18. 网络编程在线英英词典之服务器代码框架搭建(二)
  19. 多元线性回归矩阵求导
  20. 从一夜爆红到饱受争议,蚂蚁金服的相互宝如何闯关?

热门文章

  1. 怎么该软件创建桌面快捷方式
  2. linux下dynamips 与vpcs通信的实现
  3. Android开发常用开源库
  4. Docker入门书籍
  5. 管家婆SQL SERVER数据库修复案例
  6. 不二越机器人编程手册_NACHI机器人说明书.doc
  7. Android 输入法 控制 切换
  8. 阿里云入门教程搭建云数据库SQL Server
  9. 尚学堂就业怎么样?谈谈我在尚学堂的就业之路
  10. 微机原理及应用->STC25F2K60S2单片机增强型8051内核