一文帶你了解Spring核心接口Ordered的實現及應用


前言

最近在看框架的時候,發現了這個接口,在此進行總結,希望能夠給大家幫助,同時提升自己。

order接口的大體介紹

Spring框架中有這個一個接口,名字叫Ordered,聯想我們在數據庫中應用的Ordered,很容易想到它的含義就是用來排序。那么問題來了,Spring中為什么要定義這樣一個排序接口呢。我們知道spring框架使用了大量的策略設計模式。策略設計模式意味着我們的同一個接口,會有大量的不同實現。那么這么多實現,先執行哪個,后執行哪個呢。這就產生了一個排序和優先級的問題,於是Ordered接口登場,用來解決這一問題。

ordered接口的正式介紹

首先我們通過spring的源碼看一下Ordered接口,源碼如下:

public interface Ordered {
  
    int HIGHEST_PRECEDENCE = -2147483648;

    int LOWEST_PRECEDENCE = 2147483647;

    int getOrder();
  
}

從上述代碼中,我們可以看到ordered接口的實現是非常簡單的。有一個最高的優先級和一個最低的優先級,還提供了一個獲得當前實現類的order數值的方法。
spring的order中。越小的值,優先級越高,越大的值優先級越低。

ordered接口的應用

介紹完ordered接口之后,我們來看一下實際的應用場景。
有一個典型的場景,我們知道spring的事務管理是通過aop切面來實現的。當我們自己寫aop實現的時候,與事務的切面同時切到了一段代碼。那么spring應該先執行誰呢。舉一個具體的例子,我們寫了一個切換數據源的aspect切面。如果說事務的執行在數據源切換的前面,那么切換數據源就失敗了。我們肯定希望先執行切換數據源,再執行事務。
於是ordered的應用場景就來了。
假設我們寫一個下面的切面。

@Component
@Aspect
public class ChangeDataBase implements Ordered {
    
    //攔截所有的service操作
    @Pointcut("execution( * com.color.*.service.*.*(..))")
    public void point() {
    }
 
    @Before("point()")
    public void onlyReadPre() {
        DataSourceContextHolder.setDataSourceType(DataSourceType.MYSQL);
        System.out.println("數據庫切換MYSQL");
    }
 
    @After("point()")
    public void onlyReadPast() {
        DataSourceContextHolder.setDataSourceType(DataSourceType.ORACLE);
        System.out.println("數據庫切換回ORACLE");
    }
 
    @Override
    public int getOrder() {
        return 1;
    }
}

在上述代碼中,我們定義了一個切點,用於攔截所有的service的方法。然后再方法執行前,我們將數據庫切換到mysql,方法執行之后,數據庫切換成oracle。
最后重寫了ordered接口的getOrder方法。這里我們設置order的級別為1。
這個時候,我們在配置事務切面的時候。在xml中配置order。

<tx:annotation-driven transaction-manager="transactionManager" order="2"/>

如果是使用注入bean的方式的話,直接實現接口和上方一樣使用即可。
這個時候,我們就會發現。切換數據源的方法會永遠在事務之前執行,這就實現了我們的目的。

order注解的使用

讀到現在的讀者在想,還要實現接口感覺好麻煩啊,有沒有什么更方便的方法呢。當然有,我們介紹一下@Order注解。
還是先看一下order注解的源碼。

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Documented
public @interface Order {
    int value() default 2147483647;
}

默認的優先級是最小的。
我們在使用的時候,只要在類上面打上order注解即可。
我們模擬兩個類,打上order注解,然后再spring容器啟動的時候,對類進行空參構造函數加載,通過空參構造函數里面的打印情況,我們就可以看到類初始化和執行的順序。
建立我們的第一個order類。

@Component 
 
//使用order屬性,設置該類在spring容器中的加載順序
@Order(1)  
public class Order1 {
     
    private final int ORDERED = 1;
     
    public Order1(){
        System.out.println(this);
    }
  
    @Override
    public String toString() {
        return "Order1 is  loaded @ORDERED=" + ORDERED + "]";
    }
 
}

建立我們的第二個order類。

@Component 
 
//使用order屬性,設置該類在spring容器中的加載順序
@Order(2)  
public class Order2 {
     
    private final int ORDERED = 2;
     
    public Order2(){
        System.out.println(this);
    }
  
    @Override
    public String toString() {
        return "Order2 is  loaded @ORDERED=" + ORDERED + "]";
    }
 
}

啟動spring容器之后,我們看到控制台執行如下結果。

Order1 is  loaded @ORDERED=1]
Order2 is  loaded @ORDERED=2]

orderComparator的介紹

那么我們假如想知道一個類的order的值,或者想比較兩個類的order值誰大誰小,這個時候要如何操作呢,Spring貼心的給我們提供了一個類。OrderComparator,通過這個類,我們獲得實例后,使用它所提供的getOrder或者compare方法即可實現上述的需求。
我們照例還是先來看一下源碼。

public class OrderComparator implements Comparator<Object> {
    public static final OrderComparator INSTANCE = new OrderComparator();

    public OrderComparator() {
    }

    public Comparator<Object> withSourceProvider(OrderComparator.OrderSourceProvider sourceProvider) {
        return (o1, o2) -> {
            return this.doCompare(o1, o2, sourceProvider);
        };
    }

    public int compare(@Nullable Object o1, @Nullable Object o2) {
        return this.doCompare(o1, o2, (OrderComparator.OrderSourceProvider)null);
    }

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

    private int getOrder(@Nullable Object obj, @Nullable OrderComparator.OrderSourceProvider sourceProvider) {
        Integer order = null;
        if (obj != null && sourceProvider != null) {
            Object orderSource = sourceProvider.getOrderSource(obj);
            if (orderSource != null) {
                if (orderSource.getClass().isArray()) {
                    Object[] sources = ObjectUtils.toObjectArray(orderSource);
                    Object[] var6 = sources;
                    int var7 = sources.length;

                    for(int var8 = 0; var8 < var7; ++var8) {
                        Object source = var6[var8];
                        order = this.findOrder(source);
                        if (order != null) {
                            break;
                        }
                    }
                } else {
                    order = this.findOrder(orderSource);
                }
            }
        }

        return order != null ? order.intValue() : this.getOrder(obj);
    }

    protected int getOrder(@Nullable Object obj) {
        if (obj != null) {
            Integer order = this.findOrder(obj);
            if (order != null) {
                return order.intValue();
            }
        }

        return 2147483647;
    }

    @Nullable
    protected Integer findOrder(Object obj) {
        return obj instanceof Ordered ? ((Ordered)obj).getOrder() : null;
    }

    @Nullable
    public Integer getPriority(Object obj) {
        return null;
    }

    public static void sort(List<?> list) {
        if (list.size() > 1) {
            list.sort(INSTANCE);
        }

    }

    public static void sort(Object[] array) {
        if (array.length > 1) {
            Arrays.sort(array, INSTANCE);
        }

    }

    public static void sortIfNecessary(Object value) {
        if (value instanceof Object[]) {
            sort((Object[])((Object[])value));
        } else if (value instanceof List) {
            sort((List)value);
        }

    }

    @FunctionalInterface
    public interface OrderSourceProvider {
        @Nullable
        Object getOrderSource(Object var1);
    }
}

我們先來重點看一下doCompare方法。判斷邏輯如下:
若對象o1是Ordered接口類型,o2是PriorityOrdered接口類型,那么o2的優先級高於o1
若對象o1是PriorityOrdered接口類型,o2是Ordered接口類型,那么o1的優先級高於o2
其他情況,若兩者都是Ordered接口類型或兩者都是PriorityOrdered接口類型,調用Ordered接口的getOrder方法得到order值,order值越大,優先級越小
那么一句話來說就是這樣的。
OrderComparator比較器進行排序的時候,若2個對象中有一個對象實現了PriorityOrdered接口,那么這個對象的優先級更高。
若2個對象都是PriorityOrdered或Ordered接口的實現類,那么比較Ordered接口的getOrder方法得到order值,值越低,優先級越高。

再來看一下getOrder方法。
傳入一個對象后,通過provider取得原始對象。如果不為空,繼續進行判斷。
如果是數組對象,對對象進行遍歷,得到order后,跳出。如果不是數組則直接獲得對象的order。
最后如果order如果不是空,直接返回order的int值,為空的時候,通過findOrder查看,返回的是order的最大值,也就是最低優先級。

protected int getOrder(@Nullable Object obj) {
        if (obj != null) {
            Integer order = this.findOrder(obj);
            if (order != null) {
                return order.intValue();
            }
        }

        return 2147483647;
    }

總結

至此 ordered相關的東西就介紹到此為止,文中難免有不足,希望大家提出指正,感謝。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM