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

Spring中Ordered接口簡介

tle r.js 意義 supported cnblogs 模式 instance val sub

前言

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這兩個類。

關於這部分的內容,請參考樓主的另外一篇博客:http://www.cnblogs.com/fangjian0423/p/springMVC-xml-json-convert.html#analysis

既然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接口

轉自:http://www.cnblogs.com/fangjian0423/p/spring-Ordered-interface.html

Spring中Ordered接口簡介