Spring 如何保证后置处理器的执行顺序 - OrderComparator

Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html)

一、JDK 自带的比较器 Comparator

1.1 Comparable

Integer 内部实现了 Comparable 接口

public final class Integer extends Number implements Comparable<Integer> {
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
}

这样就可以用集合或数组工具进行排序,不需要再定义比较器了。

@Test
public void test() {
// 1. 集合排序
List<Integer> integerList = Arrays.asList(3, 2, 1, 5, 6);
// integerList.sort()
Collections.sort(integerList);
Assert.assertEquals(Arrays.asList(1, 2, 3, 5, 6), integerList); // 2. 数组排序
Arrays.sort(new Integer[]{3, 2, 1, 5, 6});
}

1.2 Comparator

还在另外一种情况,需要排序的对象没有实现 Comparable,那怎么办呢?JDK 提供了一个专门的比较器 Comparator。

@FunctionalInterface
public interface Comparator<T> {
// o1>o2: 1; o1=o2: 0;o1<o2: -1;
// Assert.assertEquals(-1, Integer.compare(1, 2));
int compare(T o1, T o2);
}

Collections 集合对应的排序方式如下:

public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}

二、Spring 中的比较器 OrderComparator

在 Spring 中提供了接口和注解两种方式,注意 Spring 中数值越小级别越高,位于 core 包中:

  • 一是实现 Ordered 或 PriorityOrdered 接口,PriorityOrdered 的级别要优先于 Ordered,使用 OrderComparator 比较器。

  • 二是使用 @Order(Spring 规范) 或 @Priority(JDK 规范) 注解,使用 AnnotationAwareOrderComparator 比较器。

2.1 OrderComparator

2.1.1 Ordered 接口

public interface PriorityOrdered extends Ordered {
}
public interface Ordered {
int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;
int LOWEST_PRECEDENCE = Integer.MAX_VALUE; int getOrder();
}

2.1.2 OrderComparator

// 实现 JDK 的 Comparator
public class OrderComparator implements Comparator<Object> {
@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);
// 1. PriorityOrdered 接口优先
if (p1 && !p2) {
return -1;
} else if (p2 && !p1) {
return 1;
} // 2. 比较 getOrder 的值,数值越小越优先
int i1 = getOrder(o1, sourceProvider);
int i2 = getOrder(o2, sourceProvider);
return Integer.compare(i1, i2);
}
}

使用和 JDK 一致。

2.2 AnnotationAwareOrderComparator

AnnotationAwareOrderComparator 继承自 OrderComparator 增加了 @Order(Spring 规范) 或 @Priority(JDK 规范) 注解的处理。

2.2.1 @Order

public @interface Order {
int value() default Ordered.LOWEST_PRECEDENCE;
} // javax.annotation.Priority
public @interface Priority {
int value();
}

2.2.2 AnnotationAwareOrderComparator

AnnotationAwareOrderComparator 重写了 findOrder,增加了对 @Order 或 @Priority 两个注解的处理。使用 OrderUtils 工具类。

@Override
protected Integer findOrder(Object obj) {
// Check for regular Ordered interface
Integer order = super.findOrder(obj);
if (order != null) {
return order;
} // Check for @Order and @Priority on various kinds of elements
if (obj instanceof Class) {
return OrderUtils.getOrder((Class<?>) obj);
} else if (obj instanceof Method) {
Order ann = AnnotationUtils.findAnnotation((Method) obj, Order.class);
if (ann != null) {
return ann.value();
}
} else if (obj instanceof AnnotatedElement) {
Order ann = AnnotationUtils.getAnnotation((AnnotatedElement) obj, Order.class);
if (ann != null) {
return ann.value();
}
} else {
order = OrderUtils.getOrder(obj.getClass());
if (order == null && obj instanceof DecoratingProxy) {
order = OrderUtils.getOrder(((DecoratingProxy) obj).getDecoratedClass());
}
}
return order;
}

2.3 测试

有以下 4 个类,分别是实现 PriorityOrdered 接口、实现 Ordered 接口、@Order 注解、普通 bean.

class A implements PriorityOrdered {
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}
class B implements Ordered {
@Override
public int getOrder() {
return 10;
}
}
@Order(0)
class C {
}
class D {
}

测试排序的结果:

@Test
public void test() {
List<Object> list = Arrays.asList(new D(), new C(), new B(), new A());
AnnotationAwareOrderComparator.sort(list);
// A C B D
list.forEach(o -> System.out.print(o.getClass().getSimpleName() + " "));
}

A 实现了 PriorityOrdered 接口排第一位、B 和 C 分别比较 order 值、D 排最后。


每天用心记录一点点。内容也许不重要,但习惯很重要!

Spring 如何保证后置处理器的执行顺序 - OrderComparator的更多相关文章

  1. Spring之BeanPostProcessor(后置处理器)介绍

      为了弄清楚Spring框架,我们需要分别弄清楚相关核心接口的作用,本文来介绍下BeanPostProcessor接口 BeanPostProcessor   该接口我们也叫后置处理器,作用是在Be ...

  2. Spring点滴五:Spring中的后置处理器BeanPostProcessor讲解

    BeanPostProcessor接口作用: 如果我们想在Spring容器中完成bean实例化.配置以及其他初始化方法前后要添加一些自己逻辑处理.我们需要定义一个或多个BeanPostProcesso ...

  3. spring学习四:Spring中的后置处理器BeanPostProcessor

    BeanPostProcessor接口作用: 如果我们想在Spring容器中完成bean实例化.配置以及其他初始化方法前后要添加一些自己逻辑处理.我们需要定义一个或多个BeanPostProcesso ...

  4. Spring的BeanPostProcessor后置处理器与bean的生命周期

    前言 本文将把Spring在Bean的生命周期中涉及到的后置处理器一一梳理出来,并简要说一下功能,至于每个后置处理器在实际扩展中的用处,还要后续慢慢探索总结. 正文 下面一步步跟进探寻那些后置处理器们 ...

  5. spring中Bean后置处理器实现总结

    BeanPostProcessor接口 bean的后置处理器实现功能主要是 可以在bean初始化之前和之后做增强处理.自定义MyBeanProcessor实现BeanPostProcessor接口,重 ...

  6. Spring Bean前置后置处理器的使用

    Spirng中BeanPostProcessor和InstantiationAwareBeanPostProcessorAdapter两个接口都可以实现对bean前置后置处理的效果,那这次先讲解一下B ...

  7. Spring中的后置处理器BeanPostProcessor讲解

    Spring中提供了很多PostProcessor供开发者进行拓展,例如:BeanPostProcessor.BeanFactoryPostProcessor.BeanValidationPostPr ...

  8. 2.3 spring5源码系列---内置的后置处理器PostProcess加载源码

    本文涉及主题 1. BeanFactoryPostProcessor调用过程源码剖析 2. 配置类的解析过程源码 3. 配置类@Configuration加与不加的区别 4. 重复beanName的覆 ...

  9. [原创]java WEB学习笔记101:Spring学习---Spring Bean配置:IOC容器中bean的声明周期,Bean 后置处理器

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

随机推荐

  1. 大数据入门到精通1--大数据环境下的基础文件HDFS 操作

    1.使用hdfs用户或者hadoop用户登录 2.在linux shell下执行命令 hadoop fs -put '本地文件名' hadoop fs - put '/home/hdfs/sample ...

  2. 如何从Windows中删除Node.js

    如何从Windows中删除Node.js: 1.从卸载程序卸载程序和功能. 2.重新启动(或者您可能会从任务管理器中杀死所有与节点相关的进程). 3.寻找这些文件夹并删除它们(及其内容)(如果还有). ...

  3. usb-blaster安装

    插入usb-blaster后,无法安装驱动,一直显示感叹号,更新驱动后显示“文件的哈希值不在指定的目录”这样的错误提示,解决方法如下:1.Windows键+ R,输入shutdown.exe /r / ...

  4. python 文件操作: 文件操作的函数, 模式及常用操作.

    1.文件操作的函数: open("文件名(路径)", mode = '模式', encoding = "字符集") 2.模式: r , w , a , r+ , ...

  5. GreenDao在列中的单词之间自动加_

    1.第一种情况,原字段(属性.列)是 驼峰式命名法 @Entitypublic class Employee { @Id(autoincrement = true) private Long id; ...

  6. oracle 的查询问题!!!

    问题: declare aaa integer;email varchar2(100) :='1234@aa.com';begin select count(*) into aaa from dual ...

  7. Android开发之getX,getRawX,getWidth,getTranslationX等的区别

    转载请注明出处:http://blog.csdn.net/dmk877/article/details/51550031      好久没写博客了,最近工作确实挺忙的,刚刚结束了一个TV项目的开发,对 ...

  8. NDK环境搭建方法2

    1.新建项目NDKDemo3 2.新建com.example.shixm.ndkdemo3.MyNdk.java 3.右键main文件夹,New->Folder->JNI Folder 4 ...

  9. vue bus 的使用

    简单的状态管理,可以用vue bus vue bus可以实现不同组件间.不同页面间的通信,比如我在A页面出发点击事件,要B页面发生变化,使用方法如下: 全局定义:main.js window.even ...

  10. 让Ubuntu可以压缩/解压缩RAR文件

    ubuntu刚安装的时候是不能解压rar文件的,只有在安装了解压工具之后,才可以解压. 安装:sudo apt-get install unrar卸载:sudo apt-get remove unra ...