`

Spring中Ordered接口简介

阅读更多

一.前言

        Spring中提供了一个Ordered接口。Ordered接口,顾名思义,就是用来排序的。

        Spring是一个大量使用策略设计模式的框架,这意味着有很多相同接口的实现类,那么必定会有优先级的问题。

        于是,Spring就提供了Ordered这个接口,来处理相同接口实现类的优先级问题。

 

二.Ordered接口介绍

        首先,我们来看下Ordered接口的定义:

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。

        在多个视图解释器中,也运用到了Ordered接口。如下所示:

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");
    }
  }
}

 

四.总结

        了解了Spring中Ordered接口的意义,并从实践中分析了这个接口的运用。

        这个Ordered接口也是楼主研究SpringMVC配置多个视图解析器的时候发现的,以前的时候没怎么注意,一直认为自定义配置的RequestMappingHandlerAdapter优先级会高一点,会覆盖<mvc:annotation-driven />配置的RequestMappingHandlerAdapter。 如今已明白优先级的问题。

 

文章来源:http://www.cnblogs.com/fangjian0423/p/spring-Ordered-interface.html

分享到:
评论

相关推荐

    java ordered接口应用

    Java中的`Ordered`接口主要用在需要定义顺序或者排列规则的场景,特别是在Spring框架中,它在Bean的初始化和销毁顺序、AOP切面的执行顺序等方面起到关键作用。`Ordered`接口仅包含一个方法`getOrder()`,返回一个...

    springAOP核心组件分析.pdf

    Spring会优先处理实现了PriorityOrdered接口的BeanPostProcessor,然后是实现了Ordered接口的,最后是那些没有实现优先级接口的。 3)AnnotationAwareAspectJAutoProxyCreator实现了Ordered接口,因此会在注册过程...

    Spring Annotaion Support详细介绍及简单实例

    自定义的BeanPostProcessor实现类也必须遵循Spring框架的约定,也就是实现Ordered接口。Ordered接口允许开发者控制多个BeanPostProcessor的执行顺序,这对于复杂的初始化逻辑尤为重要。 在Spring框架中,Annotation...

    springcloud gateway 全局过滤器统一签名判定.doc

    在Spring Cloud Gateway中,全局过滤器(Global Filter)是一种强大的机制,用于在请求路由到具体的服务之前或之后执行通用的处理逻辑。在这个场景中,我们关注的是如何利用全局过滤器来实现统一的签名验证,这在...

    springcloud getaway 全局过滤器.doc

    总结来说,自定义Spring Cloud Gateway全局过滤器是通过实现`GlobalFilter`接口并配置到Spring容器中完成的。这些过滤器可以用来实现诸如认证、限流、日志记录等跨路由的功能。同时,Eureka作为服务注册与发现的工具...

    Spring实例化Bean顺序

    它们的实例化顺序由`@Order`注解决定,或者通过实现`Ordered`接口来控制。 5. **InitializingBean接口**:如果Bean实现了`InitializingBean`接口,Spring会在所有必需的属性设置后调用`afterPropertiesSet()`方法。...

    springAOP核心组件分析

    3. 优先级排序:Spring通过实现PriorityOrdered接口和Ordered接口对BeanPostProcessor进行优先级排序。首先注册实现了PriorityOrdered接口的BeanPostProcessor,然后是实现了Ordered接口的BeanPostProcessor,最后...

    45 Spring中多个AOP如何协调执行?慕课专栏(1)1

    1. **实现Ordered接口**: 切面类可以实现`org.springframework.core.Ordered`接口,并重写`getOrder()`方法。返回值越小,优先级越高。例如,`LogAspect`的`getOrder()`返回5,而`LogAspect2`返回10,那么在相同的...

    Spring.MVC学习指南.pdf

    - 拦截器链中的顺序由`@Order`注解或实现Ordered接口来控制。 5. **视图技术**: - JSP,FreeMarker,Thymeleaf等视图技术可与Spring MVC集成,用于生成动态HTML页面。 - 使用ModelAndView或Model对象传递数据到...

    spring ApplicationContextInitializer实现与使用.docx

    在Spring框架中,`ApplicationContextInitializer`接口扮演着一个关键的角色,它允许开发者在Spring容器初始化时执行自定义的配置。这个接口提供了在`ConfigurableApplicationContext`的`refresh()`方法被调用之前对...

    springCloud路由网管负载均衡及拦截过滤的简单实现.

    全局过滤器在`GlobalFilter`接口中实现,例如实现日志记录: ```java @Component public class LoggingFilter implements GlobalFilter, Ordered { @Override public Mono&lt;Void&gt; filter(ServerWebExchange ...

    spring event示例

    如果你想控制事件处理的顺序,可以使用`Ordered`接口或者`@Order`注解来指定优先级。 5. **事件传播** Spring Event支持广播模式,即所有监听某一类型的事件的监听器都会收到事件通知。如果你希望事件只被一部分...

    SpringCloud Finchley Gateway 缓存请求Body和Form表单的实现

    接下来,我们需要实现`GlobalFilter`和`Ordered`接口来创建一个自定义过滤器,以缓存请求数据。这个过滤器会检查请求的MediaType,只缓存JSON和FormData类型的数据: ```java @Slf4j @Component public class ...

    Spring源码解析文件说明

    - 按照`Ordered`接口定义的顺序执行。 - 最后执行那些没有实现优先级接口的`BeanDefinitionRegistryPostProcessor`。 #### 6. 注册BeanPostProcessors - `registerBeanPostProcessors(beanFactory)` 完成以上...

    Spring-EventDemo.zip

    若要改变执行顺序,可以使用`@Order`注解或实现`Ordered`接口来指定监听器的优先级。 在"Spring-EventDemo.zip"这个压缩包中,可能包含了如上的示例代码,演示了如何创建事件、发布事件以及编写事件监听器。通过...

    spring 学习 order例子

    3. **使用Ordered接口:** 如果不希望使用注解,还可以让Bean实现`org.springframework.core.Ordered`接口,然后重写`getOrder()`方法返回一个整数值。这个值同样决定了Bean的排序。 4. **CGLIB代理与JDK动态代理...

    让spring解决控制springboot中bean的加载顺序的问题.docx

    在Spring Boot应用中,控制Bean的加载顺序是一个...理解并正确运用@DependsOn、@Order以及Ordered接口,可以有效地调整Bean的初始化顺序,以满足应用的复杂需求。同时,注意避免不必要的复杂性,保持代码的简洁和清晰。

    Spring Boot启动配置-实现任务自动执行的技术解析

    作者不仅详细讲解了如何利用这两个接口在应用程序初始化时调用指定的方法,并介绍了如何通过Ordered接口或是@Order注解自定义各任务间的执行顺序,帮助开发者灵活地进行程序的启动配置与优化。 适用人群:针对有经验...

    Spring容器扩展机制的实现原理

    如果实现多个BeanPostProcessor接口,需要实现Ordered接口来设置执行顺序。 在使用Spring时,可以通过实现BeanFactoryPostProcessor和BeanPostProcessor接口来扩展容器的功能。例如,可以使用...

    spring原理1

    2. 然后是实现了`Ordered`接口的`BeanDefinitionRegistryPostProcessor`,按照指定的顺序执行。 3. 最后,没有实现优先级或顺序接口的`BeanDefinitionRegistryPostProcessor`按默认顺序执行。 总的来说,`refresh()...

Global site tag (gtag.js) - Google Analytics