org.springframework.core.Ordered接口

本文探讨了Ordered接口的用途及实现方式,解释了如何通过优先级设置影响类的加载顺序,以PropertyPlaceholderConfigurer为例进行深入解读。

关于Ordered接口,用过的人可能知道,这里我谈下自己的理解。也希望各位大神能给予指点。

源码如下:

/**
* Interface that can be implemented by objects that should be
* orderable, for example in a Collection.
*
* <p>The actual order can be interpreted as prioritization, with
* the first object (with the lowest order value) having the highest
* priority.
*
* <p>Note that there is a 'priority' marker for this interface:
* {@link PriorityOrdered}. Order values expressed by PriorityOrdered
* objects always apply before order values of 'plain' Ordered values.
*
* @author Juergen Hoeller
* @since 07.04.2003
* @see OrderComparator
* @see org.springframework.core.annotation.Order
*/

public interface Ordered {


/**
* Useful constant for the highest precedence value.
* @see java.lang.Integer#MIN_VALUE
*/
int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;


/**
* Useful constant for the lowest precedence value.
* @see java.lang.Integer#MAX_VALUE
*/
int LOWEST_PRECEDENCE = Integer.MAX_VALUE;




/**
* Return the order value of this object, with a
* higher value meaning greater in terms of sorting.
* <p>Normally starting with 0, with <code>Integer.MAX_VALUE</code>
* indicating the greatest value. Same order values will result
* in arbitrary positions for the affected objects.
* <p>Higher values can be interpreted as lower priority. As a
* consequence, the object with the lowest value has highest priority
* (somewhat analogous to Servlet "load-on-startup" values).
* @return the order value
*/
int getOrder();


}

当然这里并不是无故提出这个接口来看的。事由是由PropertyPlaceholderConfigurer这个类的加载顺序导致的。

这个类是实现了Ordered接口并且有这样一句话

private int order = Ordered.LOWEST_PRECEDENCE; // default: same as non-Ordered

来说明PropertyPlaceholderConfigurer加载的顺序,如果你细心的话,Ordered上面的一个注释你会看到。

大概的翻译就是值越小加载优先级越高,而普通的对象我们定义的是没有实现Ordered接口的,即是他所说的

'plain' Ordered values.这样的对象的加载优先级比实现Ordered接口优先级最低的还要低。就是说虽然

PropertyPlaceholderConfigurer类的优先级是实现Ordered接口中最低的,但也比plain Object的优先级高。所以我们在

定义PropertyPlaceholderConfigurer的时候,可以把位置放后面而先用其值。如图:




2025-06-15 17:10:55.480 ERROR 17456 --- [ restartedMain] o.s.boot.SpringApplication : Application run failed org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [com.example.demo25.Demo25Application]; nested exception is org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'CORSFilter' for bean class [com.example.demo25.neu.person.filter.CORSFilter] conflicts with existing, non-compatible bean definition of same name and class [com.example.demo25.neu.department.filter.CORSFilter] at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:189) ~[spring-context-5.3.9.jar:5.3.9] at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:331) ~[spring-context-5.3.9.jar:5.3.9] at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:247) ~[spring-context-5.3.9.jar:5.3.9] at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:311) ~[spring-context-5.3.9.jar:5.3.9] at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:112) ~[spring-context-5.3.9.jar:5.3.9] at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:746) ~[spring-context-5.3.9.jar:5.3.9] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:564) ~[spring-context-5.3.9.jar:5.3.9] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-2.5.4.jar:2.5.4] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-2.5.4.jar:2.5.4] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434) ~[spring-boot-2.5.4.jar:2.5.4] at org.springframework.boot.SpringApplication.run(SpringApplication.java:338) ~[spring-boot-2.5.4.jar:2.5.4] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343) ~[spring-boot-2.5.4.jar:2.5.4] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1332) ~[spring-boot-2.5.4.jar:2.5.4] at com.example.demo25.Demo25Application.main(Demo25Application.java:10) ~[classes/:na] at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:578) ~[na:na] at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) ~[spring-boot-devtools-2.5.4.jar:2.5.4] Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'CORSFilter' for bean class [com.example.demo25.neu.person.filter.CORSFilter] conflicts with existing, non-compatible bean definition of same name and class [com.example.demo25.neu.department.filter.CORSFilter] at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.checkCandidate(ClassPathBeanDefinitionScanner.java:349) ~[spring-context-5.3.9.jar:5.3.9] at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan(ClassPathBeanDefinitionScanner.java:287) ~[spring-context-5.3.9.jar:5.3.9] at org.springframework.context.annotation.ComponentScanAnnotationParser.parse(ComponentScanAnnotationParser.java:132) ~[spring-context-5.3.9.jar:5.3.9] at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:296) ~[spring-context-5.3.9.jar:5.3.9] at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:250) ~[spring-context-5.3.9.jar:5.3.9] at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:207) ~[spring-context-5.3.9.jar:5.3.9] at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:175) ~[spring-context-5.3.9.jar:5.3.9] ... 16 common frames omitted Process finished with exit code 0
06-16
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:213) at org.springframework.boot.web.servlet.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:212) at org.springframework.boot.web.servlet.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:203) at org.springframework.boot.web.servlet.ServletContextInitializerBeans.addServletContextInitializerBeans(ServletContextInitializerBeans.java:97) at org.springframework.boot.web.servlet.ServletContextInitializerBeans.<init>(ServletContextInitializerBeans.java:86) at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.getServletContextInitializerBeans(ServletWebServerApplicationContext.java:260) at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.selfInitialize(ServletWebServerApplicationContext.java:234) at org.springframework.boot.web.embedded.tomcat.TomcatStarter.onStartup(TomcatStarter.java:53) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5211) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1393) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1383) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:134) at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:916) at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:835) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1393) at org.apache.catalina.core.ContainerBase$Start
07-12
package com.gateway; import org.reactivestreams.Publisher; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.http.HttpStatus; import org.springframework.http.server.reactive.ServerHttpResponseDecorator; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.nio.charset.StandardCharsets; import java.util.stream.Collectors; import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_PREDICATE_MATCHED_PATH_ROUTE_ID_ATTR; @Component @Order(Ordered.HIGHEST_PRECEDENCE) public class BackendExceptionConverterFilter implements GlobalFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 获取后端服务名称(从路由定义中提取) String serviceName = "degrade"; // 创建响应包装器 ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(exchange.getResponse()) { @Override public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) { HttpStatus status = getStatusCode(); if (status != null && status.isError()) { return Flux.from(body) .collectList() .flatMap(list -> { // 提取响应体内容 String responseBody = list.stream() .map(buffer -> { byte[] bytes = new byte[buffer.readableByteCount()]; buffer.read(bytes); DataBufferUtils.release(buffer); return new String(bytes, StandardCharsets.UTF_8); }) .collect(Collectors.joining()); // 抛出可被Sentinel统计的异常 throw new BackendException( serviceName, status.value(), "Service error: " + responseBody ); }); } return super.writeWith(body); } }; return chain.filter(exchange.mutate().response(decoratedResponse).build()); } } 基于这个去优化兼容无响应体的异常被sentinel正常异常统计
最新发布
10-29
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值