一文帶你瞭解Spring核心介面Ordered的實現及應用
阿新 • • 發佈:2020-05-14
### 前言
最近在看框架的時候,發現了這個介面,在此進行總結,希望能夠給大家幫助,同時提升自己。
### 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。
```
```
如果是使用注入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