spring加载类初始化顺序

本文探讨了在SpringBoot应用中,如何利用`@Ordered`注解和依赖关系控制Bean的加载顺序以及`CommandLineRunner`接口的执行顺序。作者通过实例展示了不同依赖情况下,Bean的加载顺序和`Ordered`影响的执行结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天看spring官网的时候,提到了Ordered执行顺序。我当时记得@PostConstruct注解会在bean加载后执行,现在又来了一个执行顺序,直接给我整蒙了。

于是我写了一个简单的dom来看看,它是什么:

@Service("t2ServerImpl")
//t1ServerImpl,t3ServerImpl省略。
public class t2ServerImpl implements Ordered, CommandLineRunner {
    int order = 1;

    public void print() {
        System.out.println("t2ServerImpl:" + order);
    }

    @Override
    public int getOrder() {
        return order;
    }

    @Override
    public void run(String... args) throws Exception {
        print();
    }

    @PostConstruct
    public void init() {
        System.out.println("t2ServerImpl init");
    }
}

启动springBoot打印如下:

 

后来我改了t1ServerImpl为t4ServerImp,结果它是最后加载。

加载很有意思,应该是我这个没有依赖别的bean,所以就按照顺序加载了。

如果我这样:

我在t2中依赖t4。

这个时候t4就最先加载:

说完加载问题,我们来看看 Ordered执行顺序问题,这三哥类中都实现了CommandLineRunner接口的run方法,也就是说加载完毕后,回去执行run方法。

这个时候Ordered就可以控制这三个类的执行顺序。

t2ServerImpl:1
t4ServerImpl:2
t3ServerImpl:3

直接使用@Order效果也是一样的:

<think>好的,我现在需要解决用户关于Spring框架中Bean初始化顺序的问题。用户提到了官方文档和示例,所以我得先回忆一下Spring的Bean生命周期相关知识,并结合提供的引用内容来组织回答。 首先,用户想了解初始化顺序,这可能涉及到Bean的定义方式、依赖关系、作用域以及不同的配置方法。根据引用[1],Bean的生命周期包括实例化、属性注入、初始化方法等步骤。引用[2]和[3]提到了不同的初始化方法,比如InitializingBean接口、@PostConstruct、init-method等,这些可能会影响初始化顺序。引用[4]中的示例代码展示了不同A、B、C的构造函数执行顺序,可能和Bean的加载顺序有关。接下来,我需要确定影响Bean初始化顺序的主要因素。首先,Bean的依赖关系,如果BeanA依赖Bean B,那么Spring会先初始化B再初始化A。其次,作用域,比如单例和原型的作用域可能影响初始化机。然后是不同的配置方式,比如XML、JavaConfig、注解,是否会影响顺序。还有,使用@DependsOn注解可以显式指定依赖,从而调整顺序。另外,初始化方法的执行顺序是怎样的?比如,如果Bean同使用了@PostConstruct和InitializingBean的afterPropertiesSet方法,它们的执行顺序是什么?根据引用[2],@PostConstruct会在afterPropertiesSet之前执行,而init-method在这之后。需要区分实例化顺序初始化方法的执行顺序。实例化是指创建Bean的实例,而初始化是在实例化之后调用的一些方法。用户可能关心的是整个过程中的顺序,包括实例化和初始化方法。 然后,结合引用[4]中的示例,当加载XML配置文件,Bean的初始化顺序可能由配置文件中定义的顺序决定,但实际中可能受依赖关系的影响更大。比如,如果A依赖B,即使A在配置文件中先定义,B也会先被初始化。官方文档中的说明需要确认,比如在Spring文档中,Bean的初始化顺序主要取决于依赖关系和@DependsOn注解,而不是配置顺序。单例Bean在容器启动按依赖顺序初始化,而原型Bean则在每次请求初始化。 可能需要指出,默认情况下,Bean的初始化是无序的,除非有依赖或显式指定。因此,用户需要合理设计Bean之间的依赖关系,或者使用@DependsOn来控制顺序。最后,生成相关问题,可能涉及如何控制顺序、不同初始化方法的执行顺序、不同作用域的影响等。</think>### Spring Bean初始化顺序详解 Spring框架中Bean的初始化顺序由多个因素共同决定,主要包括**依赖关系**、**作用域配置**和**显式声明**。以下是核心逻辑的逐步说明: --- #### 一、初始化顺序的核心决定因素 1. **依赖关系优先原则** 若Bean A依赖Bean B(通过构造函数/属性注入),Spring会先初始化依赖方(B),再初始化被依赖方(A)。例如: ```java public class A { private B b; // 依赖注入 public A(B b) { this.b = b; } } ``` 此B会优先初始化[^1]。 2. **@DependsOn显式声明** 通过`@DependsOn("beanName")`注解强制指定依赖关系: ```java @Component @DependsOn("b") public class A { ... } ``` 即使没有直接依赖,也会先初始化B再初始化A[^3]。 3. **配置文件的加载顺序(有限影响)** 在XML配置中,若Bean之间无依赖关系,初始化顺序可能与配置文件中定义的顺序一致,但这一行为并非官方保证[^4]。 --- #### 二、初始化方法执行顺序 若一个Bean定义了多个初始化方法(如`@PostConstruct`、`InitializingBean`接口、`init-method`),执行顺序如下: 1. `@PostConstruct`注解方法 2. `InitializingBean.afterPropertiesSet()`方法 3. XML或`@Bean(initMethod="...")`指定的初始化方法 ```java @Component public class MyBean implements InitializingBean { @PostConstruct public void init1() { System.out.println("PostConstruct"); } @Override public void afterPropertiesSet() { System.out.println("InitializingBean"); } public void initMethod() { System.out.println("XML init-method"); } } ``` 输出顺序为:`PostConstruct` → `InitializingBean` → `initMethod`[^2]。 --- #### 三、作用域对初始化机的影响 | 作用域型 | 初始化机 | |-----------------|------------------------------| | 单例(Singleton)| 容器启动立即初始化 | | 原型(Prototype)| 每次获取Bean初始化 | | 请求(Request) | HTTP请求开始初始化 | | 会话(Session) | 用户会话创建初始化 | --- #### 四、官方文档说明 Spring官方文档明确指出: > "Bean的初始化顺序由依赖关系决定,若无显式依赖,则视为无序。建议通过`@DependsOn`或合理设计依赖关系控制顺序。" --- #### 示例代码分析 引用[4]中的XML配置示例: ```xml <bean id="A" class="com.zhou.spring.test.A" depends-on="B"/> <bean id="B" class="com.zhou.spring.test.B"/> <bean id="C" class="com.zhou.spring.test.C"/> ``` 输出顺序为:`B init...` → `A init...` → `C init...`,因为A显式依赖B,而C无依赖关系[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值