上一篇介绍了如何代理,本篇介绍获得所有合适的切面类:

AbstractAdvisorAutoProxyCreator

public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator

AbstractAdvisorAutoProxyCreator 继承了AbstractAutoProxyCreator,前一篇文章已经详细分析了这个类,该类的方法getAdvicesAndAdvisorsForBean是抽象的,子类可以定义自己的逻辑;看下AbstractAdvisorAutoProxyCreator 是如何定义的:

 protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {// 找合适的切面 没有的话就返回nullList<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);if (advisors.isEmpty()) {return DO_NOT_PROXY;}return advisors.toArray();}

 protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {// 找到所有的候选的切面类List<Advisor> candidateAdvisors = findCandidateAdvisors();// 在所有的切面中找出匹配该bean的切面List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);extendAdvisors(eligibleAdvisors);if (!eligibleAdvisors.isEmpty()) {// 对候选的切面类进行排序eligibleAdvisors = sortAdvisors(eligibleAdvisors);}// 返回合适的切面return eligibleAdvisors;}

这个方法有三个功能:

  1. 找出所有的切脉
  2. 选出候选的切面
  3. 对候选切面排序

找出所有的切面

 public List<Advisor> findAdvisorBeans() {// 缓存了切脉类的名称String[] advisorNames = this.cachedAdvisorBeanNames;// 如果缓存中没有数据,就直接中bean工厂中找书所有Advisor类型的切面类。if (advisorNames == null) {advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Advisor.class, true, false);// 设置缓存this.cachedAdvisorBeanNames = advisorNames;}// bean工厂中如果没有切面类的话,返回一个没有数据集合。if (advisorNames.length == 0) {return new ArrayList<>();}List<Advisor> advisors = new ArrayList<>();for (String name : advisorNames) {// 这里的方法返回值是org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#isEligibleAdvisorBean定义的,返回的永远是true.if (isEligibleBean(name)) {if (this.beanFactory.isCurrentlyInCreation(name)) {if (logger.isTraceEnabled()) {logger.trace("Skipping currently created advisor '" + name + "'");}}else {try {// 实例化,放入集合advisors.add(this.beanFactory.getBean(name, Advisor.class));}catch (BeanCreationException ex) {Throwable rootCause = ex.getMostSpecificCause();if (rootCause instanceof BeanCurrentlyInCreationException) {BeanCreationException bce = (BeanCreationException) rootCause;String bceBeanName = bce.getBeanName();if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {if (logger.isTraceEnabled()) {logger.trace("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;}}}}return advisors;}

从工厂找出所有Advisor类型的bean,实例化;


选出候选的切面

 public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {if (candidateAdvisors.isEmpty()) {return candidateAdvisors;}List<Advisor> eligibleAdvisors = new ArrayList<>();for (Advisor candidate : candidateAdvisors) {// 这一步是处理IntroductionAdvisor 不用管,暂时用不到if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {eligibleAdvisors.add(candidate);}}boolean hasIntroductions = !eligibleAdvisors.isEmpty();for (Advisor candidate : candidateAdvisors) {if (candidate instanceof IntroductionAdvisor) {// already processedcontinue;}// 每个界面类匹配。if (canApply(candidate, clazz, hasIntroductions)) {eligibleAdvisors.add(candidate);}}return eligibleAdvisors;}

遍历所有的切面,如果能匹配上,就添加候选集合。

 public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {// IntroductionAdvisor的匹配。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) {// 如果类不匹配,直接返回了 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 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) {// 找到该类的中声明的方法,注意这里找的是声明的方法。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;}

举个例子就明白了:

Service1 extends Service2 implements Service

调用ClassUtils.getAllInterfacesForClassAsSet方法时,会得到Service2,Service;

这里有个引申的问题:事务的注解注释的接口上可以用吗?当然可以,本类中没有找到,会从接口中找。

对候选的切面排序

 public int compare(@Nullable Object o1, @Nullable Object o2) {return doCompare(o1, o2, null);}private int doCompare(@Nullable Object o1, @Nullable Object o2, @Nullable OrderSourceProvider sourceProvider) {boolean p1 = (o1 instanceof PriorityOrdered);boolean p2 = (o2 instanceof PriorityOrdered);if (p1 && !p2) {return -1;}else if (p2 && !p1) {return 1;}int i1 = getOrder(o1, sourceProvider);int i2 = getOrder(o2, sourceProvider);return Integer.compare(i1, i2);}

通过order的顺序排序,值越小,越靠前。也就是越先执行。

@Aspect注解的类呢?怎么没发现加进来呢? 下面就介绍下一个子类:AspectJAwareAdvisorAutoProxyCreator

AspectJAwareAdvisorAutoProxyCreator

该方法重写的两个方法:sortAdvisors,shouldSkip

shouldSkip方法

该方法时判断类是否要跳过,不用代理。
重写的方法,兼容了父类的逻辑,添加了新的逻辑:如果被代理的类是@aspect注解注释的,则跳过;从这个快可以看到@aspect注解的类的方法被解析为了AspectJPointcutAdvisor类型的切面。

 protected boolean shouldSkip(Class<?> beanClass, String beanName) {// TODO: Consider optimization by caching the list of the aspect namesList<Advisor> candidateAdvisors = findCandidateAdvisors();for (Advisor advisor : candidateAdvisors) {if (advisor instanceof AspectJPointcutAdvisor &&((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {return true;}}return super.shouldSkip(beanClass, beanName);}

sortAdvisors

排序:同样就兼容父类逻辑,添加自己的逻辑

 protected List<Advisor> sortAdvisors(List<Advisor> advisors) {List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors = new ArrayList<>(advisors.size());for (Advisor element : advisors) {partiallyComparableAdvisors.add(new PartiallyComparableAdvisorHolder(element, DEFAULT_PRECEDENCE_COMPARATOR));}// 这里进行排序List<PartiallyComparableAdvisorHolder> sorted = PartialOrder.sort(partiallyComparableAdvisors);if (sorted != null) {List<Advisor> result = new ArrayList<>(advisors.size());for (PartiallyComparableAdvisorHolder pcAdvisor : sorted) {result.add(pcAdvisor.getAdvisor());}return result;}else {return super.sortAdvisors(advisors);}}

首先还是根据order排序:如果order一样,同时是一个Aspect中解析出来的。走一下逻辑:

 public int compare(Advisor o1, Advisor o2) {int advisorPrecedence = this.advisorComparator.compare(o1, o2);if (advisorPrecedence == SAME_PRECEDENCE && declaredInSameAspect(o1, o2)) {advisorPrecedence = comparePrecedenceWithinAspect(o1, o2);}return advisorPrecedence;}
 private int comparePrecedenceWithinAspect(Advisor advisor1, Advisor advisor2) {boolean oneOrOtherIsAfterAdvice =(AspectJAopUtils.isAfterAdvice(advisor1) || AspectJAopUtils.isAfterAdvice(advisor2));int adviceDeclarationOrderDelta = getAspectDeclarationOrder(advisor1) - getAspectDeclarationOrder(advisor2);if (oneOrOtherIsAfterAdvice) {// the advice declared last has higher precedenceif (adviceDeclarationOrderDelta < 0) {// advice1 was declared before advice2// so advice1 has lower precedencereturn LOWER_PRECEDENCE;}else if (adviceDeclarationOrderDelta == 0) {return SAME_PRECEDENCE;}else {return HIGHER_PRECEDENCE;}}else {// the advice declared first has higher precedenceif (adviceDeclarationOrderDelta < 0) {// advice1 was declared before advice2// so advice1 has higher precedencereturn HIGHER_PRECEDENCE;}else if (adviceDeclarationOrderDelta == 0) {return SAME_PRECEDENCE;}else {return LOWER_PRECEDENCE;}}}

这里就是处理before,after这些的切面顺序。注意:我们不是找到所有的切面嘛,如果是通过aspect注解解析出来的会有一定顺序的:around,before,after,afterreturn,afterthrow,通过排序后就变成了:
afterthrow, afterreturn, after, around, before;通过该顺序和执行链就知道了顺序了:

afterthrow{afterreurn{after{around{before{真正的方法}}}}
}

around before…
before…
当前执行的方法。。
around after…
after
after return…

知道顺序了,可以是没有看到对@aspect注解的解析呀?来看这个类:AnnotationAwareAspectJAutoProxyCreator

AnnotationAwareAspectJAutoProxyCreator

主要看这个重写的方法:

 protected List<Advisor> findCandidateAdvisors() {// A父类中找到所有的切面List<Advisor> advisors = super.findCandidateAdvisors();// 解析Aspect类if (this.aspectJAdvisorsBuilder != null) {advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());}return advisors;}
 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<>();//得到所有的注册的beanString[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);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;}// 如果是@aspect注解注释的,才可以if (this.advisorFactory.isAspect(beanType)) {aspectNames.add(beanName);AspectMetadata amd = new AspectMetadata(beanType, beanName);if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {// 封装为一个aspect工厂实例,有工厂,有bean名称,取实例很容易MetadataAwareAspectInstanceFactory factory =new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);// 解析这个Aspect类。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();}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;}

解析出切面类:

 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)) {// 创建切面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.for (Field field : aspectClass.getDeclaredFields()) {Advisor advisor = getDeclareParentsAdvisor(field);if (advisor != null) {advisors.add(advisor);}}return advisors;}

主要看两个方法:
getAdvisorMethods(aspectClass)
getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName)

getAdvisorMethods

 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);}}, ReflectionUtils.USER_DECLARED_METHODS);// 找到了所有没有用Pointcut标注的方法;进行排序,注意这个顺序就是://Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.classmethods.sort(METHOD_COMPARATOR);return methods;}

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;}// 都封装为InstantiationModelAwarePointcutAdvisorImpl切面return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,this, aspectInstanceFactory, declarationOrderInAspect, aspectName);}

再该切面内部进行具体的实例化:

 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 classif (!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:// candidateAdviceMethod:执行的方法// aspectInstanceFactory:aspect实例。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-AOP】自动代理类AnnotationAwareAspectJAutoProxyCreator相关推荐

  1. Spring AOP自动创建代理 和 ProxyFactoryBean创建代理

    Advice 通知类型 AOP联盟为通知Advice定义了org.aopalliance.aop.Interface.Advice,Spring按照通知Advice在目标方法的连接点位置,可以分为5种 ...

  2. Spring AOP动态代理

    导入依赖: <dependency><groupId>org.springframework</groupId><artifactId>spring-a ...

  3. Spring AOP动态代理实现,解决Spring Boot中无法正常启用JDK动态代理的问题

    Spring AOP动态代理实现,解决Spring Boot中无法正常启用JDK动态代理的问题 参考文章: (1)Spring AOP动态代理实现,解决Spring Boot中无法正常启用JDK动态代 ...

  4. 求求你,下次面试别再问我什么是 Spring AOP 和代理了!

    作者 | 倪升武 责编 | 胡巍巍 我们知道,Spring 中 AOP 是一大核心技术,也是面试中经常会被问到的问题,最近我在网上也看到很多面试题,其中和 Spring AOP 相关的就有不少,这篇文 ...

  5. Spring AOP理论 +代理模式详解

    目录 1.理解AOP 1.1.什么是AOP 1.2.AOP体系与概念 1.3.Spring AOP 通知的执行顺序 2.代理模式 2.1.静态代理 2.2.静态代理的缺点 3.动态代理 JDK 动态代 ...

  6. Spring AOP 与代理详解

    SpringBoot 系列教程 - 源码地址:https://github.com/laolunsi/spring-boot-examples 大家知道我现在还是一个 CRUD 崽,平时用 AOP 也 ...

  7. Spring Aop编写代理半自动 aopalliance 和weaver 包(免费)

    在自行练习spring aop的半自动编写代理时需要这两个jar包,但是发现很多需要收费,表示很无语,这里奉上免费下载链接 aopalliance-alpha1: 链接: https://pan.ba ...

  8. Spring AOP动态代理-切面

    2019独角兽企业重金招聘Python工程师标准>>> 在上一节中,我们通过Advice可以对目标类进行增强,使得目标类在调用的时候可以执行增强类中的代码,但是,增强类适配了目标类中 ...

  9. Spring :Spring Aop 创建代理

    1.美图 2.概述 寻找代理,请参考以前的文章 3.前文概要 /*** Wrap the given bean if necessary, i.e. if it is eligible for bei ...

  10. Spring : Spring Aop 创建代理

    1.美图 2.概述 3.postProcessAfterInitialization /*** Create a proxy with the configured interceptors if t ...

最新文章

  1. ActiveMQ死信队列使用
  2. eclipse解决maven编码UTF-8的不可映射字符
  3. html5之form表单
  4. diamond operator is not supported in -source 1.5和source release 8 requires target release 1.8的问题
  5. DFS应用——找出无向图的割点
  6. 图像风格迁移(Neural Style)简史
  7. js小数运算出现多为小数问题_js 数字加减乘除精度问题,解决小数点后多位小数...
  8. android surface编程,Android编程之SurfaceView实例详解
  9. 中后台管理信息系统通用原型方案、业务中台管理系统、业务中台架构、管理信息系统、订单管理、客户管理、货源管理、财务管理、客服管理、营销管理、办公申请、协作管理、CMS、OA、CRM、ERP、Axure
  10. LeetCode 1059. All Paths from Source Lead to Destination
  11. keyset与entryset
  12. 计算机毕业设计——基于Spring Boot框架的网络游戏虚拟交易平台的设计与实现
  13. 短时傅里叶变换STFT(matlab)
  14. 广义相对论-学习记录1-第一章-历史回顾
  15. 驱动学习笔记 IRP
  16. my name is van
  17. redis课件DIY
  18. 影视作品烂到至高无上的境界不是槽点满满
  19. js按钮确认删除提示
  20. 小甲鱼28课文件:因为懂你,总结反思

热门文章

  1. html 显示编辑xml文件,如何将 XML 文件显示为 HTML 表格展示
  2. java shell文件_Java 文件读写示例1
  3. Anormaly_Detection_with_Keras
  4. linux命令行中的大括号,linux命令行学习(19):花括号扩展(brace expansion)
  5. pix2pixhd_图像翻译三部曲:pix2pix, pix2pixHD, vid2vid
  6. android 布局覆盖 超出一部分_Android 开发者峰会 2019 常见问题解答
  7. 使用boost中的线程池
  8. java基础学习(9)堆和栈的区别详解
  9. Elpscrk:功能强大的智能字典生成器
  10. w8fuckcdn 通过扫描全网绕过CDN获取网站IP地址