侧边栏壁纸
博主头像
Setyg的博客

当秋风染红落叶的时候,就是新生~

  • 累计撰写 86 篇文章
  • 累计创建 66 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

Spring Boot 的 @Configuration 指定加载顺序实践

Setyg
2026-09-14 / 0 评论 / 0 点赞 / 5 阅读 / 0 字

Spring Boot 的 @Configuration 指定加载顺序实践

项目里配置类一多,就容易产生「谁先加载」的疑问:两个配置类里定义了同类型的 Bean 会不会冲突?A 配置里注入的 List 顺序为什么每次不一样?本文整理用 @Order 指定配置类顺序的写法,并重点澄清它到底能控制什么、不能控制什么 —— 后者往往才是踩坑的地方。

一、用 @Order 指定配置类优先级

可以使用 Spring 框架提供的 @Order 注解来指定配置类的优先级。@Order 注解接受一个整数值,数字越小优先级越高,意味着该配置类会更早被处理。

import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;

@Configuration
@Order(1) // 数字越小,优先级越高
public class FirstConfig {
    // 配置内容
}

@Configuration
@Order(2)
public class SecondConfig {
    // 配置内容
}

补一个稍完整、能直接看到效果的例子:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;

@Configuration
@Order(1) // 优先级高
public class FirstConfig {

    @Bean
    public FirstService firstService() {
        return new FirstService();
    }
}

@Configuration
@Order(2) // 优先级低
public class SecondConfig {

    @Bean
    public SecondService secondService() {
        return new SecondService();
    }
}

等价的另一种写法:实现 Ordered 接口

@Order 本质上是 Ordered 接口的注解形式。当顺序值需要动态计算(例如从配置项、环境变量推导)时,直接实现接口更灵活:

import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;

@Configuration
public class FirstConfig implements Ordered {

    @Override
    public int getOrder() {
        return 1; // 数字越小,优先级越高
    }
}

注意:不要把 @Order 和 getOrder() 同时写在一个类上,Spring 的排序比较器会优先读取注解值,容易造成「改了代码没生效」的困惑。

二、@Order 实际影响什么

把 @Order 加在 @Configuration 类上,能产生下面这些可靠的效果:

  1. 配置类被解析、处理的先后顺序。Spring 在处理配置类时会用 AnnotationAwareOrderComparator 对配置类候选排序,@Order 小的配置类先被处理,其内部的 @Bean 定义也先被注册(先注册的 BeanDefinition 不会覆盖后注册的,这点在处理同类型 Bean 时很关键)。

  2. 同一类型多个 Bean 注入集合时的顺序。这是最实用的场景。向 List<T>、T[] 注入多个实现时,Spring 会按 order 值排序。

  3. @Import 进来的配置类同样参与排序,所以拆分配置模块时可以靠 @Order 表达依赖关系。

集合注入顺序示例

public interface MyCustomizer {
    void customize();
}

@Configuration
public class CustomizerConfig {

    @Bean
    @Order(1)
    public MyCustomizer aCustomizer() {
        return () -> System.out.println("A customizer");
    }

    @Bean
    @Order(2)
    public MyCustomizer bCustomizer() {
        return () -> System.out.println("B customizer");
    }
}

@Service
public class MyService {

    private final List<MyCustomizer> customizers;

    // 注入顺序固定为 A → B,与 @Order 一致
    public MyService(List<MyCustomizer> customizers) {
        this.customizers = customizers;
    }
}

提示:这里 @Order 是写在 @Bean 方法上的。工厂方法上的 @Order 会被 Spring 解析为该 Bean 的排序值,用于集合注入;把它写在 @Configuration 类上则只影响配置类本身。

三、@Order 不影响什么(重点)

这是最容易误解的部分。以下情况 @Order 帮不上忙:

期望

@Order 能否做到

说明

控制 Bean 的初始化(实例化)顺序

❌ 不能

Bean 创建顺序由依赖关系决定,与 order 无关

控制同一个类中多个 @Bean 方法的调用先后

❌ 不能

由依赖关系与注册顺序决定

控制 @PostConstruct、InitializingBean 的触发先后

❌ 不能

跟随 Bean 创建顺序

控制配置类的处理顺序

✅ 能

排序发生在配置类解析阶段

控制集合注入的顺序

✅ 能

写在 @Bean 方法上生效

一句话总结:@Order 管的是「排序」,不是「先后执行的时序」。如果 FirstConfig 的 Bean 依赖 SecondConfig 的 Bean,那么无论 @Order 写多少,被依赖的那个一定先创建 —— 依赖关系永远优先于 @Order。

四、真正控制初始化顺序的手段

1. @DependsOn —— 显式声明依赖

没有注入关系但需要保证创建顺序时使用:

@Bean
@DependsOn("dataSourceInitializer")
public CacheManager cacheManager() {
    return new ConcurrentMapCacheManager();
}

被 @DependsOn 指定的 Bean 会先于当前 Bean 创建。

2. 构造器注入 / @Autowired —— 利用天然依赖

最推荐的方式:让依赖关系真实存在,Spring 自然按拓扑顺序创建,不需要任何顺序注解。

3. 想要「全部 Bean 就绪后再做事」

  • 实现 SmartInitializingSingleton#afterSingletonsInstantiated();

  • 或监听 ApplicationReadyEvent / ContextRefreshedEvent。

这类场景不要试图用 @Order 解决。

五、自动配置类的顺序

如果你是写 Starter、或者想调整 Spring Boot 自动配置的先后,用的是另一套注解,与普通 @Configuration 上的 @Order 不是一回事:

注解 / 配置

作用

@AutoConfigureBefore

声明本自动配置在指定类之前

@AutoConfigureAfter

声明本自动配置在指定类之后

@AutoConfigureOrder

指定绝对顺序,仅对自动配置类有效

@AutoConfiguration

Boot 2.7+ 的组合注解,等价于 @Configuration(proxyBeanMethods = false) 加上述排序注解

AutoConfiguration.imports

Boot 2.7+ 的注册文件:META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports;更早版本用 spring.factories

@AutoConfiguration(after = DataSourceAutoConfiguration.class)
public class MyAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public MyService myService() {
        return new MyService();
    }
}

关键区别:@AutoConfigureOrder 只对通过自动配置机制(imports / spring.factories)注册的类生效;写在业务代码里的普通 @Configuration 上加它没有效果,那种场景要用 @Order。

六、常见问题

1. 两个配置类定义了同类型 Bean,谁生效?

默认情况下后注册的定义会因 spring.main.allow-bean-definition-overriding 的取值而不同:Boot 2.1 之后默认为 false,重复定义会直接启动失败。使用 @ConditionalOnMissingBean 才是消除冲突的正解,靠 @Order 抢注册顺序并不可靠。

2. 用 @Order 能控制 @PropertySource 的覆盖关系吗?

属性源的加入顺序确实会跟随配置类的处理顺序,但不建议依赖这一点做配置覆盖 —— 这类需求请使用多环境配置(application-{profile}.yml)、spring.config.import 或命令行参数,语义更明确、也不受重构影响。

3. @Order 的值该取多少?

Spring 提供两个常量参考:Ordered.HIGHEST_PRECEDENCE(Integer.MIN_VALUE)与 Ordered.LOWEST_PRECEDENCE(Integer.MAX_VALUE,也是未标注时的默认值)。业务代码建议从 0 开始,按 10、20、30 的步长递增,留出插入空间,避免后期调整时大面积改值。

4. order 值相同时会怎样?

顺序不确定,取决于注册顺序,不同环境、不同版本可能不一致。需要保证顺序的场景,请为每个配置分配不同值。

七、小结

  1. @Order 接受整数,数字越小优先级越高,配置类会更早被处理;也可以改为实现 Ordered 接口。

  2. 可靠效果只有两个:配置类处理顺序与集合注入顺序(后者需要把 @Order 写在 @Bean 方法上)。

  3. 它不控制 Bean 的初始化时序 —— 那是依赖关系的地盘,用构造器注入或 @DependsOn 来管。

  4. 自动配置类的先后请用 @AutoConfigureBefore / @AutoConfigureAfter / @AutoConfigureOrder,普通业务配置类上写这些无效。

  5. 业务代码里给 order 留出步长(10、20、30),顺序才长期可控。

0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区