1 前言
上节我们看过了代理对象执行方法的大致过程,我们留着通知器链的具体执行没说,这节我们先讲解一下通知器的执行顺序。
通知器或者叫拦截器,叫法不一样,这里我们还是都统一叫通知器吧。
这是我的AOP类,方便调试。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 @Component 2 @Aspect 3 public class MyAspect { 4 5 @Pointcut("execution( * com.virtuous.demo.spring.cycle.a.A.*(..))") 6 public void myPointCut() { 7 } 8 9 10 @After("myPointCut()") 11 public void myAfter(JoinPoint point) { 12 System.out.println("myAfter"); 13 } 14 15 @Before("myPointCut()") 16 public void myBefore(JoinPoint point) { 17 System.out.println("myBefore"); 18 } 19 20 21 @Around("myPointCut()") 22 public Object around(ProceedingJoinPoint joinPoint) throws Throwable { 23 System.out.println("around before"); 24 Object res = joinPoint.proceed(); 25 System.out.println("around after"); 26 return res; 27 } 28 29 @AfterThrowing(value = "myPointCut()", throwing = "e") 30 public void afterThrowing(Exception e) { 31 System.out.println("afterThrowing"); 32 } 33 34 35 @AfterReturning(value = "myPointCut()") 36 public void afterReturning() { 37 System.out.println("afterReturning"); 38 } 39 40 41 }View Code
2 通知器类型的演变过程
首先我们简单回忆一下,我们的通知器的一个类型变化过程,辅助你更好的理解,因为边看边调试中间做了好几次转换封装有点麻,我大概汇总下:
- XML配置解析或者是注解方式的解析,都会生成对应的通知类
- 创建代理的时候,对我们的通知类又进行的一个wrap操作,也就是类型的转变
- 执行代理的时候,把我们的通知器转变成拦截器(当前有的通知类其实已经实现了拦截器的接口,所以有的就不需要进行适配器的变换)
那么我大概总结了一下,我是针对我的Aspect每个阶段调试总结的哈,可能每个人版本或者配置不一样,但是应该都差不多。
调试结果:
3 通知器的顺序来源
我们的通知器是有顺序的,那这个顺序是什么时候确定的呢,这个顺序有涉及到两个地方:
- 第一个排序是在获取所有的通知器的时候,也就是解析有哪些通知器的时候,会对一个Aspect里的所有通知进行排序(记住这里只是对一个Aspect里的)
- 第二次排序是在创建代理的时候,获取当前bean适合的通知器的时候会做排序
3.1 第一次排序
我们先来看下第一次排序时机的调用过程,如图:
那么我们看下源码的过程:
private List<Method> getAdvisorMethods(Class<?> aspectClass) { List<Method> methods = new ArrayList<>(); ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter); if (methods.size() > 1) { // 对某个Aspect里的所有通知器进行排序 methods.sort(adviceMethodComparator); } return methods; }
private static final Comparator<Method> adviceMethodComparator; static { /** * 整体的排序思路就是:先按下边顺序排,然后通知器类型相同的再按字符串排序(字母首字母以及长度升序) * 注意看这个顺序:Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class */ Comparator<Method> adviceKindComparator = new ConvertingComparator<>( new InstanceComparator<>( Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class), (Converter<Method, Annotation>) method -> { AspectJAnnotation<?> ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method); return (ann != null ? ann.getAnnotation() : null); }); Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName); adviceMethodComparator = adviceKindComparator.thenComparing(methodNameComparator); }
public InstanceComparator(Class<?>... instanceOrder) { Assert.notNull(instanceOrder, "'instanceOrder' array must not be null"); this.instanceOrder = instanceOrder; } @Override public int compare(T o1, T o2) { int i1 = getOrder(o1); int i2 = getOrder(o2); return (Integer.compare(i1, i2)); } /** * InstanceComparator * instanceOrder也就是你刚才传过来的注解类的顺序 * @param object * @return */ private int getOrder(@Nullable T object) { if (object != null) { for (int i = 0; i < this.instanceOrder.length; i++) { if (this.instanceOrder[i].isInstance(object)) { return i; } } } return this.instanceOrder.length; }
看一下我的排序结果:
所以针对第一次排序,大概思路就是:
- 每个Aspect先按照Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class的顺序排好,至于Aspect和Aspect谁在前谁在后这里不处理;
- 通知类型相同的情况下按照字符串顺序升序排序。
3.2 第二次排序
接下里我们看下第二次排序的时机,这次排序有点懵,东西很多,我先前置几个知识点,否则有点晕。
3.2.1 OrderComparator
Spring有个排序器OrderComparator,这个的排序规则我们看下源码:
/** * @see Ordered 接口 有个getOrder() 方法 你懂的就是返回你的排序值 * @see PriorityOrdered 接口 没有任何方法 只是一个标志 就是标志我最强我是老大都听我的 * @see org.springframework.core.annotation.AnnotationAwareOrderComparator 对注解的增强 增加OrderComparator对注解排序值的支持 */ public class OrderComparator implements Comparator<Object> { public static final OrderComparator INSTANCE = new OrderComparator(); public Comparator<Object> withSourceProvider(OrderSourceProvider sourceProvider) { return (o1, o2) -> doCompare(o1, o2, sourceProvider); } /** * !!!优先级排序 越小优先级越高 比如a的优先级高于b 那么 a.compare(b) == -1 别搞晕奥 * 我们只看当前类的OrderComparator * 在不考虑OrderSourceProvider的前提下,那影响排序的因素就是 PriorityOrdered和Ordered接口两种方式 * a、b 比较的话 * 1、有且只有一个实现了PriorityOrdered 那谁的优先级就高 * 2、都实现了或者都没实现的话,就getOrder()获取排序值 * 没实现的话 会有默认值Ordered.LOWEST_PRECEDENCE * 然后就比较排序值大小 小的优先级高 * */ @Override 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); } protected int getOrder(@Nullable Object obj) { if (obj != null) { Integer order = findOrder(obj); if (order != null) { return order; } } return Ordered.LOWEST_PRECEDENCE; // 没有排序值的话默认为Integer.MAX_VALUE,int最大值 别晕 最大表示优先级越低 } }
正如我上边注释的哈,影响它的排序大小的因素有是否有实现PriorityOrdered接口标识、是否有实现Ordered接口都没有的话,也会有默认值,这样来比较。
3.2.2 AnnotationAwareOrderComparator
AnnotationAwareOrderComparator这个类是上边类的子类,对上边的类的增强,主要就是findOrder的时候,先调用父类的方法,父类为空的话这个类会去从注解上去继续取排序值,这样来切进来逻辑。
@Override @Nullable protected Integer findOrder(Object obj) { // 先调用父类的 Integer order = super.findOrder(obj); if (order != null) { return order; } // 父类为空的话则找注解上有没有排序值 return findOrderFromAnnotation(obj); } // 具体怎么拿的就不看了 @Nullable private Integer findOrderFromAnnotation(Object obj) { AnnotatedElement element = (obj instanceof AnnotatedElement ? (AnnotatedElement) obj : obj.getClass()); MergedAnnotations annotations = MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY); Integer order = OrderUtils.getOrderFromAnnotations(element, annotations); if (order == null && obj instanceof DecoratingProxy) { return findOrderFromAnnotation(((DecoratingProxy) obj).getDecoratedClass()); } return order; }
AnnotationAwareOrderComparator,它带来了注解的增强 @Order(可以在类上、方法上、属性上)、@Priority(可以在类上、方法参数上),它影响的是findOrder的增强, OrderComparator先去找排序值 找不到的话才会AnnotationAwareOrderComparator注解中去找,最后都找不到的话会有默认值Ordered.LOWEST_PRECEDENCE。
3.2.3 PartialOrder.sort偏序排序
偏序排序相对应的有个全序排序,全序排序我们都知道就是整个数组都是有顺序的,那么偏序排序就是部分排序,不是所有的都有序,只是数组中的某些元素有先后顺序,这样的排序为偏序排序。
我们先看下偏序排序的方法入口:
// 也就是说集合中的元素都要是PartialComparable类型的 public static <T extends PartialComparable> List<T> sort(List<T> objects) {} public interface PartialComparable { /** * 主要排序 * 1 表示大于other * -1表示小于other * 0 表示两者无关系 * @param other * @return */ int compareTo(Object other); /** * 次要排序 * 也就是对主要排序的辅助排序 * !!当主要排序结果为0时,才会调用该方法进行次要排序 * @param other * @return */ int fallbackCompareTo(Object other); }
那么对应到我们这里通知器里的实现是怎么呢,我们看下:
/** * 我们通知器排序的偏序排序的元素类 * 即每个元素都要实现的PartialComparable的元素包装类 */ private static class PartiallyComparableAdvisorHolder implements PartialComparable { private final Advisor advisor; private final Comparator<Advisor> comparator; /** * 我们看到其实就是把通知和一个比较器传进来 * @param advisor * @param comparator */ public PartiallyComparableAdvisorHolder(Advisor advisor, Comparator<Advisor> comparator) { this.advisor = advisor; this.comparator = comparator; } /** * 这个是什么呢,就是我们刚才讲的上边的偏序排序的 主要排序 * 那么这里的具体实现是什么呢? * 可以看到它是调用了参数里的comparator进行比较的 * @param obj * @return */ @Override public int compareTo(Object obj) { Advisor otherAdvisor = ((PartiallyComparableAdvisorHolder) obj).advisor; return this.comparator.compare(this.advisor, otherAdvisor); } /** * 次要排序 这里返回的0 也就是不排序不做处理 * @param obj * @return */ @Override public int fallbackCompareTo(Object obj) { return 0; } }
3.2.4 通知器集合的比较器-AspectJPrecedenceComparator
好,那么我们来看下参数里的比较器,也就是AspectJPrecedenceComparator的源码:
partiallyComparableAdvisors.add(new PartiallyComparableAdvisorHolder(advisor, DEFAULT_PRECEDENCE_COMPARATOR)); private static final Comparator<Advisor> DEFAULT_PRECEDENCE_COMPARATOR = new AspectJPrecedenceComparator(); // 这里就是我们的通知器比较器 public AspectJPrecedenceComparator() { public AspectJPrecedenceComparator() { // 这个默认初始化的advisorComparator 其实也就是带注解的增强排序器AnnotationAwareOrderComparator this.advisorComparator = AnnotationAwareOrderComparator.INSTANCE; } @Override public int compare(Advisor o1, Advisor o2) { // 首先是AnnotationAwareOrderComparator进行排序 int advisorPrecedence = this.advisorComparator.compare(o1, o2); // 如果等于0表示两者没关系,并且是在一个Aspect里则调用comparePrecedenceWithinAspect 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)); /** * 调用两个的getAspectDeclarationOrder 进行比较 * 这里给你们埋个引子,adviceDeclarationOrderDelta其实会一直等于0的 * !!!因为getAspectDeclarationOrder值所有的通知器都是相等的,并且都是0 */ int adviceDeclarationOrderDelta = getAspectDeclarationOrder(advisor1) - getAspectDeclarationOrder(advisor2); // 如果有后置通知器 if (oneOrOtherIsAfterAdvice) { // adviceDeclarationOrderDelta小于0 说明advisor1的值小 说明优先级高 那么就应该排在前边 就返回-1 if (adviceDeclarationOrderDelta < 0) { return LOWER_PRECEDENCE; } // adviceDeclarationOrderDelta大于0 说明advisor1的值大 说明优先级低 那么就应该排在后边 就返回1 else if (adviceDeclarationOrderDelta == 0) { return SAME_PRECEDENCE; } // 等于0 返回0不处理 else { return HIGHER_PRECEDENCE; } } // 下边一样 else { if (adviceDeclarationOrderDelta < 0) { return HIGHER_PRECEDENCE; } else if (adviceDeclarationOrderDelta == 0) { return SAME_PRECEDENCE; } else { return LOWER_PRECEDENCE; } } } }
3.2.5 通知器外层的包装-InstantiationModelAwarePointcutAdvisorImpl
我们上边提过,在解析配置或者XML的AOP配置时,都会把每个通知类外边包一层InstantiationModelAwarePointcutAdvisorImpl,我们回忆下部分源码哈,如果这个你不知道的话,建议你再看一遍。
// 记住这里的factory类型,下边会用到
MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName); // 获取通知器 List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
// 参数aspectInstanceFactory就是上边传过来的factory public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) { // 获取 aspectClass 和 aspectName Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass(); String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName(); validate(aspectClass); MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory = new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory); List<Advisor> advisors = new ArrayList<>(); // getAdvisorMethods 用于返回不包含 @Pointcut 注解的方法 for (Method method : getAdvisorMethods(aspectClass)) { // 为每个方法分别调用 getAdvisor 方法 看这里的0 对应的参数就是下边方法的declarationOrder Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName); if (advisor != null) { advisors.add(advisor); } }
// aspectInstanceFactory就是上边的new LazySingletonAspectInstanceFactoryDecortor(aspectInstantceFactory) 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; } // 创建 Advisor 实现类 return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod, this, aspectInstanceFactory, declarationOrderInAspect, aspectName); }
我们还要再仔细看一个细节就是InstantiationModelAwarePointcutAdvisorImpl这个类实现了AspectJPrecedenceInformation,而AspectJPrecedenceInformation又继承了Ordered接口,那么说明什么呢,也就是我们的每个通知器都实现了Ordered接口,都有getOrder()方法咯,那么我们看下getOrder()的实现:
// InstantiationModelAwarePointcutAdvisorImpl里的getOrder()
@Override public int getOrder() { return this.aspectInstanceFactory.getOrder(); } // aspectInstanceFactory是什么?就是上边的new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory); // 那么继续进入LazySingletonAspectInstanceFactoryDecorator的getOrder() @Override public int getOrder() { return this.maaif.getOrder(); } // 继续进入this.maaif 也就是BeanFactoryAspectInstanceFactory的getOrder() @Override public int getOrder() { // this.name也就是通知器所属的Aspect的bean的name Class<?> type = this.beanFactory.getType(this.name); if (type != null) { // 当切面类即Aspect实现了Ordered并且Aspect是单例的 就返回切面类Aspect的getOrder() if (Ordered.class.isAssignableFrom(type) && this.beanFactory.isSingleton(this.name)) { return ((Ordered) this.beanFactory.getBean(this.name)).getOrder(); } // 否则就返回切面类Aspect注解上的@Order的值,没有的话默认Ordered.LOWEST_PRECEDENCE return OrderUtils.getOrder(type, Ordered.LOWEST_PRECEDENCE); }
// 默认返回 return Ordered.LOWEST_PRECEDENCE; }
好了,到这里为止第二次排序过程中的几个很重要的知识点就介绍完了,随着介绍其实第二次排序怎么排我们大概也有了眉目,我们看下源码入口:
protected List<Advisor> sortAdvisors(List<Advisor> advisors) { List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors = new ArrayList<>(advisors.size()); for (Advisor advisor : advisors) { partiallyComparableAdvisors.add( new PartiallyComparableAdvisorHolder(advisor, DEFAULT_PRECEDENCE_COMPARATOR)); } // 就是这里把每个通知器包装成PartialComparable,然后调用PartialOrder.sort进行一个偏序排序 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); } }
偏序排序的比较器也就是AspectJPrecedenceComparator的compare方法,那我们再来看下:
public interface PartialComparable { @Override public int compare(Advisor o1, Advisor o2) { /** * 首先advisorComparator就是AnnotationAwareOrderComparator进行排序 * AnnotationAwareOrderComparator排序我们说过取值优先级从PriorityOrdered接口、Ordered接口、@Order注解、@Prio * 我们上边看到我们的每个通知器其实都实现了Ordered接口, * getOrder的值的取法: * 1、切面类Aspect有没有实现Ordered接口,并且是单例的就返回切面类的getOrder值 * 2、否则就从切面类Aspect上取@Order注解的值, 没有注解返回Integer.MAX 即最小优先级 * 说白了: * 1、一个切面类Aspect里的所有通知器的getOrder都是相等的 默认都是Integer.MAX * 2、@Order能写在方法在但是对于通知器的方法不好使不管用的 * 3、当切面类Aspect实现了Ordered接口的话,实现getOrder()接口 * 4、当切面类Aspect上有注解@Order的话 取注解的值 当然实现Ordered接口优先于注解@Order */ int advisorPrecedence = this.advisorComparator.compare(o1, o2); // comparePrecedenceWithinAspect这个其实没啥用 因为在一个切面里通知器的排序值都是相等的 if (advisorPrecedence == SAME_PRECEDENCE && declaredInSameAspect(o1, o2)) { advisorPrecedence = comparePrecedenceWithinAspect(o1, o2); } return advisorPrecedence; } }
好了,到这里我们通知器的顺序来源,就结束了,不知道你晕没晕,这里我们总结就一句话:其实比较的不是每个通知器,而是比较的是每个通知器所属的Aspect的排序值。
这句话你认可不,每个通知器其实都是一组一组的排序,比如有Aspect1、Aspect2, 假如Aspect1的优先级高,那么通知器的顺序就是Aspect1所有的通知器、然后是Aspect2所有的通知器,Aspect1或者Aspect2里每个器又是按照【Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class】的顺序排列,相同类型的按照方法的全名字(包名+类名+方法名)即字符串升序排列;
4 小结
好了,这节我们主要讲了一下通知器的顺序问题,东西很多,但是最后其实看起来能控制顺序的也就是Aspect自己,当然有理解错误的地方欢迎指正哈,下节我们看看执行过程。
标签:拦截器,return,int,Spring,getOrder,通知,AOP,排序,public From: https://www.cnblogs.com/kukuxjx/p/17142351.html