1. 程式人生 > >Spring中Ordered介面簡介

Spring中Ordered介面簡介

目錄

前言

Spring中提供了一個Ordered介面。Ordered介面,顧名思義,就是用來排序的。

Spring是一個大量使用策略設計模式的框架,這意味著有很多相同介面的實現類,那麼必定會有優先順序的問題。

於是,Spring就提供了Ordered這個介面,來處理相同介面實現類的優先順序問題。

Ordered介面介紹

首先,我們來看下Ordered介面的定義:

public interface Ordered {
  
    int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;

    int LOWEST_PRECEDENCE = Integer.MAX_VALUE;

    int getOrder();
  
}

只有1個方法:getOrder();  2個變數:最高階(數值最小)和最低階(數值最大)。

OrderComparator類:實現了Comparator的一個比較器。

提供了3個靜態排序方法:sort(List<?> list)、sort(Object[] array)、sortIfNecessary(Object value)。根據OrderComparator對陣列和集合進行排序。

sortIfNecessary方法內部會判斷value引數是Object[]還是List型別,然後使用Object[]引數的sort方法和List引數的sort方法進行排序。

我們看下這個比較器的compare方法:

public int compare(Object o1, Object o2) {
  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);
  int i2 = getOrder(o2);
  return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;  
}

PriorityOrdered是個介面,繼承自Ordered介面,未定義任何方法。

這段程式碼的邏輯:

  1. 若物件o1是Ordered介面型別,o2是PriorityOrdered介面型別,那麼o2的優先順序高於o1

  2. 若物件o1是PriorityOrdered介面型別,o2是Ordered介面型別,那麼o1的優先順序高於o2

  3. 其他情況,若兩者都是Ordered介面型別或兩者都是PriorityOrdered介面型別,呼叫Ordered介面的getOrder方法得到order值,order值越大,優先順序越小

簡單概括就是:

  OrderComparator比較器進行排序的時候,若2個物件中有一個物件實現了PriorityOrdered介面,那麼這個物件的優先順序更高。

  若2個物件都是PriorityOrdered或Ordered介面的實現類,那麼比較Ordered介面的getOrder方法得到order值,值越低,優先順序越高。

Ordered介面在Spring中的使用

以SpringMVC為例,舉例Ordered介面的運用。

<mvc:annotation-driven/>

這段配置在*-dispatcher.xml中定義的話,那麼SpringMVC預設會注入RequestMappingHandlerAdapter和RequestMappingHandlerMapping這兩個類。

既然SpringMVC以及預設為我們注入了RequestMappingHandlerAdapter和RequestMappingHandlerMapping這兩個類,我們是否可以再次配置這兩個類?

答案當然是可以的。

RequestMappingHandlerMapping:

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
  <property name="interceptors">
    <bean class="package.interceptor.XXInterceptor"/>
  </property>  
  <property name="order" value="-1"/>
</bean>

RequestMappingHandlerAdapter:

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
  <property name="messageConverters">
    <list>
      <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
      <bean class="org.springframework.http.converter.StringHttpMessageConverter">
        <property name="supportedMediaTypes">
          <list>
            <value>text/plain;charset=UTF-8</value>
          </list>
        </property>
      </bean>
      <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
      <bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>
      <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
      <bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
        <constructor-arg ref="marshaller"/>
      </bean>
    </list>
  </property>  
  <property name="customArgumentResolvers">
    <bean class="org.format.demo.support.resolve.FormModelMethodArgumentResolver"/>
  </property>
  <property name="webBindingInitializer">
    <bean class="org.format.demo.support.binder.MyWebBindingInitializer"/>
  </property>
  <property name="order" value="-1"/>
</bean>

當我們配置了annotation-driven以及這兩個bean的時候。Spring容器就有了2個RequestMappingHandlerAdapter和2個RequestMappingHandlerMapping。

DispatcherServlet內部有HandlerMapping(RequestMappingHandlerMapping是其實現類)集合和HandlerAdapter(RequestMappingHandlerAdapter是其實現類)集合。


private List<HandlerMapping> handlerMappings;

private List<HandlerAdapter> handlerAdapters;
 

我們看下這兩個集合的初始化程式碼:

很明顯使用了我們提到的OrderComparator比較器進行了排序。

下面我們看下annotation-driven程式碼配置的RequestMappingHandlerMapping和RequestMappingHandlerAdapter。

RequestMappingHandlerMapping預設會設定order屬性為0,RequestMappingHandlerAdapter沒有設定order屬性。

我們進入RequestMappingHandlerMapping和RequestMappingHandlerAdapter程式碼裡面看看它們的order屬性是如何定義的。

AbstractHandlerMethodAdapter是RequestMappingHandlerAdapter的父類。

AbstractHandlerMapping是RequestMappingHandlerMapping的父類。

我們看到,RequestMappingHandlerMapping和RequestMappingHandlerAdapter沒有設定order屬性的時候,order屬性的預設值都是Integer.MAX_VALUE,即優先順序最低。 

PS:

如果配置了<mvc:annotation-driven />,又配置了自定義的RequestMappingHandlerAdapter,並且沒有設定RequestMappingHandlerAdapter的order值,那麼這2個RequestMappingHandlerAdapter的order值都是Integer.MAX_VALUE。那麼誰的優先順序高呢? 答案: 誰先定義的,誰優先順序高。 <mvc:annotation-driven />配置在自定義的RequestMappingHandlerAdapter配置之前,那麼<mvc:annotation-driven />配置的RequestMappingHandlerAdapter優先順序高,反之自定義的RequestMappingHandlerAdapter優先順序高。

如果配置了<mvc:annotation-driven />,又配置了自定義的RequestMappingHandlerMapping,並且沒有設定RequestMappingHandlerMapping的order值。那麼<mvc:annotation-driven />配置的RequestMappingHandlerMapping優先順序高,因為<mvc:annotation-driven />內部會設定RequestMappingHandlerMapping的order,即0。

這點讀者可自行測試。

在多個檢視直譯器中,也運用到了Ordered介面。

總結

瞭解了Spring中Ordered介面的意義,並從實踐中分析了這個介面的運用。

這個Ordered介面也是樓主研究SpringMVC配置多個檢視解析器的時候發現的,以前的時候沒怎麼注意,一直認為自定義配置的RequestMappingHandlerAdapter優先順序會高一點,會覆蓋<mvc:annotation-driven />配置的RequestMappingHandlerAdapter。 如今已明白優先順序的問題。

希望這篇文章能幫助讀者瞭解Ordered介面。