👈👈👈 欢迎点赞收藏关注哟
首先分享之前的所有文章 >>>> 😜😜😜
文章合集 : 🎁 juejin.cn/post/694164...
Github : 👉 github.com/black-ant
CASE 备份 : 👉 gitee.com/antblack/ca...
一. 前言
之前看了基于 @Configuration 的Bean 优先级控制,这还不够,在 Spring 中还有很多种优先级控制的方式。
这一篇就来说说关于 Order 在实际应用中应该怎么玩,以及他的问题以及原理。
二. 基本使用
在 Spring 中的 Order 特性有2种实现 :
- 基于 @Order 注解对Bean优先级做控制
- 基于 Order接口实现 Bean 优先级控制
java
@Component
@Order(2)
public class SecondComponent implements Ordered {
// 如果是实现的接口,则需要继承对应的方法
@Override
public int getOrder() {
return 1;
}
}
三. 简单看原理
3.1 先从微观看原理
先从微观入手,Order 处理流程里面最核心的类就是 AnnotationAwareOrderComparator ,在这个类里面会进行 Order 的查找和比较 ,核心源码就一个 :
java
protected Integer findOrder(Object obj) {
// 如果是实现的 Order 接口 ,则通过 Order 接口的 getOrder 方法
Integer order = super.findOrder(obj);
if (order != null) {
return order;
}
// 尝试通过注解获得 Order 优先级
return findOrderFromAnnotation(obj);
}
// 补充一 : 注解获取优先级的流程
OrderUtils.getOrderFromAnnotations(element, annotations)
private static Integer findOrder(MergedAnnotations annotations) {
// 核心一 : 如果拿到了 Order 注解就直接返回
MergedAnnotation<Order> orderAnnotation = annotations.get(Order.class);
// 核心二 : 如果没有拿到 Order 注解会去获取 "javax.annotation.Priority"
MergedAnnotation<?> priorityAnnotation = annotations.get(JAVAX_PRIORITY_ANNOTATION);
}
- 细节点 : 在 OrderUtils 中会对注解值进行缓存
private static final Map<AnnotatedElement, Object> orderCache = new ConcurrentReferenceHashMap<>(64);
目的 :
- 细节点 : javax.annotation.Priority 注解有什么用
Priority 对应的是 @Priority(2) 注解 。
3.2 从宏观看流程
SpringOrder 的使用最后还是集中到 AnnotationAwareOrderComparator
的调用上面,从使用的方法上就不难看出使用的场景 :
Order 在这些流程里面是怎么控制顺序的
我们以 Spring.factories 流程的加载流程 :(createSpringFactoriesInstances)
这也是 Order 最常见的用法之一,当我们通过 Spring.factories 定义自动配置的工厂方法时,在获取到所有的 Factories 类后,会调用 AnnotationAwareOrderComparator.sort(instances)
对这些工厂方法排序
四. 业务使用场景
4.1 Configuration 上面的使用
java
@Slf4j
@Configuration
public class ConfigurationOrder {
@Bean
@Order(10)
public ConfigBeanB getConfigBeanB() {
return new ConfigBeanB();
}
@Bean
@Order(1)
public ConfigBeanA getConfigBeanA() {
return new ConfigBeanA();
}
}
- 该场景下 Order
只支持同一个
@Configuration 的排序 不能
通过在 @Configuration
类上添加 @Order 实现 Configuration Bean 的排序不能
通过 @Component
+Order
接口 或者 @Order 注解实现Bean 控制
也就是说 ,以下这种方式是不会生效的
4.2 Spring.factories 启动类通过 Order 排序
java
public class SelfApplicationContextInitializer implements ApplicationContextInitializer, Ordered {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
}
@Override
public int getOrder() {
return 99;
}
}
基于 Spring.factories 的自动配置是可以通过 Order 定义优先级的
4.3 AOP 类使用 Order
Aop 中可能在业务场景中不会特意定义 Order ,一般一个切面对应的就是一个业务,但是如果是一些开源框架或者原生代码的 AOP ,又想在他们切面之前做一些定制,那么这个就有必要了 :
java
@Aspect
@Component
@Order(33)
public class AspectOrder {
@Around("execution(* com.test.bean.demo.service.BeanOne.*(..))")
public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("AspectOrder 执行目标方法之前的操作");
Object result = joinPoint.proceed();
return result;
}
}
4.4 Listener 中使用 Order
java
@Component
@Order(11)
public class FirstListener implements ApplicationListener<SpringApplicationEvent> {
@Override
public void onApplicationEvent(SpringApplicationEvent event) {
log.info("FirstListener");
}
}
- 只不过不同于 Bean 加载的流程 ,Listener Order 会自己去拿方法的 Order
4.5 影响 ApplicationRunner 的使用
- ❗注意 : @Order 不影响 Bean 的创建过程,但是会影响 ApplicationRunner 这些依赖的执行过程
java
@Service
@Order(1000)
public class BeanOne implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
logger.info("------> BeanOne Run <-------");
}
}
当 实现了 ApplicationRunner 接口的情况下,会按照 @Order 的顺序进行执行。
👉👉同理还有 CommandLineRunner!!
4.6 其他 Order 生效的地方
- EnvironmentPostProcessor 的执行顺序
- 待后续补充~~~
五. 问题
5.1 为什么 Order + @Component 不会生效
直接的原因在于 AnnotationAwareOrderComparator 没有在 @Bean 加载过程中被调用。
在 Bean 加载过程中 ,除了通过包的扫描流程控制Bean的顺序外 ,就只能通过 @DependOn 注解了。
详细可以看这一篇 # 写好 Spring Starter : 控制好Bean的加载顺序与原理
5.2 为什么那些 ApplicationRunner 中 Order 又可以生效?
java
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
// 在这个环节中,Bean 的顺序按照Order进行排序
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<>(runners)) {
//.......
}
}
从这里也可以推断出 ,Bean 加载时是不会按照 Order 排序的。
总结
闲时写了一篇,可能会有遗漏,但是这篇里面的都代码验证过,应该不会有啥问题。