一.前言
Spring中提供了一个Ordered接口。Ordered接口,顾名思义,就是用来排序的。
Spring是一个大量使用策略设计模式的框架,这意味着有很多相同接口的实现类,那么必定会有优先级的问题。
于是,Spring就提供了Ordered这个接口,来处理相同接口实现类的优先级问题。
?
二.Ordered接口介绍
首先,我们来看下Ordered接口的定义:
class="java">package org.springframework.core; public abstract interface Ordered { public static final int HIGHEST_PRECEDENCE = Integer.MIN_VALUE; public static final int LOWEST_PRECEDENCE = Integer.MAX_VALUE; public abstract 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) { return doCompare(o1, o2, null); } private int doCompare(Object o1, Object o2, OrderSourceProvider sourceProvider) { boolean p1 = o1 instanceof PriorityOrdered; boolean p2 = o2 instanceof PriorityOrdered; if ((p1) && (!p2)) { return -1; } if ((p2) && (!p1)) { return 1; } int i1 = getOrder(o1, sourceProvider); int i2 = getOrder(o2, sourceProvider); return i1 > i2 ? 1 : i1 < i2 ? -1 : 0; } private int getOrder(Object obj, OrderSourceProvider sourceProvider) { Integer order = null; if (sourceProvider != null) { Object orderSource = sourceProvider.getOrderSource(obj); if ((orderSource != null) && (orderSource.getClass().isArray())) { Object[] sources = ObjectUtils.toObjectArray(orderSource); for (Object source : sources) { order = findOrder(source); if (order != null) { break; } } } else { order = findOrder(orderSource); } } return order != null ? order.intValue() : getOrder(obj); } protected int getOrder(Object obj) { Integer order = findOrder(obj); return order != null ? order.intValue() : Integer.MAX_VALUE; }
PriorityOrdered是个接口,继承自Ordered接口,未定义任何方法。
package org.springframework.core; public abstract interface PriorityOrdered extends 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://bijian1013.iteye.com/blog/2310236
?
既然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;
我们看下这两个集合的初始化代码:
private void initHandlerMappings(ApplicationContext context) { this.handlerMappings = null; if (this.detectAllHandlerMappings) { Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerMappings = new ArrayList(matchingBeans.values()); AnnotationAwareOrderComparator.sort(this.handlerMappings); } } else { try { HandlerMapping hm = (HandlerMapping)context.getBean("handlerMapping", HandlerMapping.class); this.handlerMappings = Collections.singletonList(hm); } catch (NoSuchBeanDefinitionException localNoSuchBeanDefinitionException) {} }
private void initHandlerAdapters(ApplicationContext context) { this.handlerAdapters = null; if (this.detectAllHandlerAdapters) { Map<String, HandlerAdapter> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerAdapters = new ArrayList(matchingBeans.values()); AnnotationAwareOrderComparator.sort(this.handlerAdapters); } } else { try { HandlerAdapter ha = (HandlerAdapter)context.getBean("handlerAdapter", HandlerAdapter.class); this.handlerAdapters = Collections.singletonList(ha); } catch (NoSuchBeanDefinitionException localNoSuchBeanDefinitionException) {} } if (this.handlerAdapters == null) { this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class); if (this.logger.isDebugEnabled()) { this.logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default"); } } }
很明显使用了AnnotationAwareOrderComparator(OrderComparator的子类)比较器进行了排序。
?
下面我们看下annotation-driven代码配置的RequestMappingHandlerMapping和RequestMappingHandlerAdapter。
WebMvcConfigurationSupport.java
@Bean public RequestMappingHandlerMapping requestMappingHandlerMapping() { RequestMappingHandlerMapping handlerMapping = createRequestMappingHandlerMapping(); handlerMapping.setOrder(0); handlerMapping.setInterceptors(getInterceptors()); handlerMapping.setContentNegotiationManager(mvcContentNegotiationManager()); handlerMapping.setCorsConfigurations(getCorsConfigurations()); PathMatchConfigurer configurer = getPathMatchConfigurer(); if (configurer.isUseSuffixPatternMatch() != null) { handlerMapping.setUseSuffixPatternMatch(configurer.isUseSuffixPatternMatch().booleanValue()); } if (configurer.isUseRegisteredSuffixPatternMatch() != null) { handlerMapping.setUseRegisteredSuffixPatternMatch(configurer.isUseRegisteredSuffixPatternMatch().booleanValue()); } if (configurer.isUseTrailingSlashMatch() != null) { handlerMapping.setUseTrailingSlashMatch(configurer.isUseTrailingSlashMatch().booleanValue()); } if (configurer.getPathMatcher() != null) { handlerMapping.setPathMatcher(configurer.getPathMatcher()); } if (configurer.getUrlPathHelper() != null) { handlerMapping.setUrlPathHelper(configurer.getUrlPathHelper()); } return handlerMapping; }
@Bean public RequestMappingHandlerAdapter requestMappingHandlerAdapter() { List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList(); addArgumentResolvers(argumentResolvers); List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList(); addReturnValueHandlers(returnValueHandlers); RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter(); adapter.setContentNegotiationManager(mvcContentNegotiationManager()); adapter.setMessageConverters(getMessageConverters()); adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer()); adapter.setCustomArgumentResolvers(argumentResolvers); adapter.setCustomReturnValueHandlers(returnValueHandlers); if (jackson2Present) { List<RequestBodyAdvice> requestBodyAdvices = new ArrayList(); requestBodyAdvices.add(new JsonViewRequestBodyAdvice()); adapter.setRequestBodyAdvice(requestBodyAdvices); List<ResponseBodyAdvice<?>> responseBodyAdvices = new ArrayList(); responseBodyAdvices.add(new JsonViewResponseBodyAdvice()); adapter.setResponseBodyAdvice(responseBodyAdvices); } AsyncSupportConfigurer configurer = new AsyncSupportConfigurer(); configureAsyncSupport(configurer); if (configurer.getTaskExecutor() != null) { adapter.setTaskExecutor(configurer.getTaskExecutor()); } if (configurer.getTimeout() != null) { adapter.setAsyncRequestTimeout(configurer.getTimeout().longValue()); } adapter.setCallableInterceptors(configurer.getCallableInterceptors()); adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors()); return adapter; }
RequestMappingHandlerMapping默认会设置order属性为0,RequestMappingHandlerAdapter没有设置order属性。
?
我们进入RequestMappingHandlerMapping和RequestMappingHandlerAdapter代码里面看看它们的order属性是如何定义的。
public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered { private int order = Integer.MAX_VALUE;
AbstractHandlerMethodAdapter是RequestMappingHandlerAdapter的父类。
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered { private int order = Integer.MAX_VALUE;
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。
?
DispatcherServlet.java
private void initViewResolvers(ApplicationContext context) { this.viewResolvers = null; if (this.detectAllViewResolvers) { Map<String, ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false); if (!matchingBeans.isEmpty()) { this.viewResolvers = new ArrayList(matchingBeans.values()); AnnotationAwareOrderComparator.sort(this.viewResolvers); } } else { try { ViewResolver vr = (ViewResolver)context.getBean("viewResolver", ViewResolver.class); this.viewResolvers = Collections.singletonList(vr); } catch (NoSuchBeanDefinitionException localNoSuchBeanDefinitionException) {} } if (this.viewResolvers == null) { this.viewResolvers = getDefaultStrategies(context, ViewResolver.class); if (this.logger.isDebugEnabled()) { this.logger.debug("No ViewResolvers found in servlet '" + getServletName() + "': using default"); } } }
在多个视图解释器中,也运用到了Ordered接口。
?
四.总结
了解了Spring中Ordered接口的意义,并从实践中分析了这个接口的运用。
?
这个Ordered接口也是楼主研究SpringMVC配置多个视图解析器的时候发现的,以前的时候没怎么注意,一直认为自定义配置的RequestMappingHandlerAdapter优先级会高一点,会覆盖<mvc:annotation-driven />配置的RequestMappingHandlerAdapter。 如今已明白优先级的问题。
?
文章来源:http://www.cnblogs.com/fangjian0423/p/spring-Ordered-interface.html