SpringBoot教程(9) @DependsOn 设置Bean依赖 结合@Lazy 修改Bean加载顺序

本文介绍了如何使用@DependsOn和@Lazy注解来控制Spring框架中Bean的加载顺序。通过示例展示了Teacher和LateStudent两个类,分别使用@DependsOn确保Teacher先于LateStudent加载,使用@Lazy实现LateStudent的懒加载。

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

一、需要@DependsOn的场景

在开发中,如果有2个类A和B,且B要监听A,则希望B在A之前加载到容器中。

但是Spring默认是根据文件夹中类名的顺序加载,例如字母A在B之前,则会先加载A。

@DependsOn注解可以设置Bean直接的依赖关系,被依赖的会先创建加载到Spring容器中。

下面举例:有一个老师类:Teacher,一个迟到学生类:LateStudent。

老师要检查哪些学生迟到,则老师得先到学校,在教室门口等着迟到的学生。

对于Spring容器而言,得先加载Teacher,后加载LateStudent,这样Teacher才能监听所有的LateStudent。

二、实验示例

在这里插入图片描述

1. Teacher类

@Component("teacher")
public class Teacher {

    public Teacher() {
        System.out.println("创建了老师");
    }
}

2. LateStudent类

@Component("lateStudent")
public class LateStudent {

    public LateStudent() {
        System.out.println("创建了学生");
    }
}

3. 配置类

Teacher ,LateStudent 都在bean包下

@Configuration
@ComponentScan(value = "bean")
public class MySpringConfig {
}

4. 测试类

public class DependsOnTest {
    public static void main(String[] args) {
        //创建容器
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext("config");

        ac.start();
    }
}

运行结果:
这个不是我们想要的,但是学生类在老师类上方,所以先加载了学生

创建了学生
创建了老师

5. 添加@DependsOn,设置依赖关系

添加@DependsOn,设置依赖关系

@Component("lateStudent")
@DependsOn("teacher")
public class LateStudent {

    public LateStudent() {
        System.out.println("创建了学生");
    }
}

运行结果:

创建了老师
创建了学生

三、用@Lazy懒加载

以前博客介绍过@Lazy,@Lazy只对单例有效。
单例Bean懒加载 @Lazy的使用和失效情况

1. 用@Lazy方式让学生在后面加载

去掉@DependsOn(“teacher”),加上@Lazy

@Lazy
@Component("lateStudent")
public class LateStudent {

    public LateStudent() {
        System.out.println("创建了学生");
    }
}
public class DependsOnTest {
    public static void main(String[] args) {
        //创建容器
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext("config");

        Object lateStudent = ac.getBean("lateStudent");

        ac.start();
    }
}

结果如下

创建了老师
创建了学生

四、@DependsOn和@Lazy都存在的情况

1. 假设被依赖的Teacher用了@Lazy

此时DependsOnTest 没有调用LateStudent ,即没有下面的语句

Object lateStudent = ac.getBean("lateStudent");

老师:

@Lazy
@Component("teacher")
public class Teacher {

    public Teacher() {
        System.out.println("创建了老师");
    }
}

学生:

@Component("lateStudent")
@DependsOn("teacher")
public class LateStudent {

    public LateStudent() {
        System.out.println("创建了学生");
    }
}

结果如下:

创建了老师
创建了学生

结果说明老师Teacher 类上的@Lazy失效了。

因为启动容器创建LateStudent 时,发现用到Teacher,所以就先加载了Teacher,导致Teacher的 @Lazy失效了

<think>好的,用户现在问的是关于Spring框架中的@DependsOn注解,特别是解释@DependsOn({ "liquibase", "listSetMapper" })的作用。我需要先回顾一下@DependsOn的基本用法和目的。 首先,@DependsOn用于显式指定Bean之间的依赖关系,确保某些Bean在初始化之前,它所依赖的其他Bean已经初始化完成。这对于解决那些不是通过直接引用或注入方式建立的隐式依赖非常有用。 用户给出的例子是@DependsOn({ "liquibase", "listSetMapper" }),说明当前标注的Bean需要依赖于名为"liquibase"和"listSetMapper"的两个Bean。接下来,我需要分步骤思考可能的应用场景和原因。 首先想到的是Liquibase,它是一个数据库迁移工具,通常在应用启动时执行数据库脚本,比如创建表或插入初始数据。如果某个Bean(比如数据访问层或服务层)需要依赖数据库结构已经准备就绪,那么必须确保Liquibase已经完成执行。这时候使用@DependsOn("liquibase")就能保证顺序。 然后是"listSetMapper",这可能是一个自定义的Bean,比如用于对象映射的工具(类似MapStruct或Dozer)。如果某个Bean在初始化时需要用到这个映射器,那么必须确保它在映射器初始化之后才被创建,避免因为映射器未准备好而导致的错误。 接下来需要考虑用户可能的实际使用场景。比如,用户可能在配置类或某个服务类上使用了这个注解,以确保在数据库迁移完成后,并且对象映射器已经初始化之后,再初始化当前Bean。例如,一个需要访问数据库的服务类,或者需要在启动时进行数据初始化的组件。 另外,用户可能遇到的问题是没有明确依赖导致启动顺序错误,比如数据库迁移未完成时,某个Bean尝试访问数据库表,导致异常。或者映射器尚未初始化,导致对象转换失败。这时候使用@DependsOn可以显式控制Bean的创建顺序,避免这类问题。 还需要考虑是否有其他方式可以达到同样的效果,比如通过构造函数注入或方法注入隐式建立依赖,但有时候这些方式不够直观或者无法覆盖所有情况,这时候@DependsOn就显得很有用。 此外,需要提醒用户注意Bean的名称是否正确,是否与Liquibase和listSetMapper的Bean名称一致,否则可能导致依赖无效。例如,Liquibase在Spring Boot中默认的Bean名称是否是"liquibase",用户是否自定义了Bean的名称,或者是否有多个同类型的Bean导致名称冲突。 最后,可能需要给出一个具体的代码示例,说明如何在Spring中使用@DependsOn,并解释每个部分的作用,帮助用户更好地理解应用场景和正确使用方法。</think>--- ### **@DependsOn({ "liquibase", "listSetMapper" }) 的详细解释** #### **1. 注解作用** `@DependsOn` 是 Spring 框架提供的注解,**显式声明当前 Bean 对其他 Bean 的初始化依赖**。其核心功能是: **强制 Spring 容器按指定顺序初始化 Bean**,确保被依赖Bean(如 `liquibase` 和 `listSetMapper`)在当前 Bean 初始化之前已经完成创建和初始化。 --- ### **2. 典型使用场景** #### **场景 1:数据库迁移依赖** - **Liquibase** 是数据库版本控制工具,通常在应用启动时执行 SQL 脚本(如建表、初始化数据)。 - **问题**:如果某个 Service 或 Repository Bean 在 Liquibase 完成数据库变更前就初始化,可能导致访问缺失的表或字段而报错。 - **解决方案**:在依赖数据库结构的 Bean 上添加 `@DependsOn("liquibase")`,确保数据库就绪后再初始化这些 Bean。 #### **场景 2:工具类初始化依赖** - **listSetMapper** 可能是自定义的映射工具(如对象转换器),需要在其他组件使用前完成配置。 - **问题**:如果某 Bean 在初始化时直接调用 `listSetMapper` 的方法,但 `listSetMapper` 尚未初始化,会抛出 `NullPointerException`。 - **解决方案**:通过 `@DependsOn("listSetMapper")` 确保依赖的工具类优先初始化。 --- ### **3. 代码示例** ```java @Component @DependsOn({ "liquibase", "listSetMapper" }) // 关键注解 public class OrderService { @Autowired private OrderRepository orderRepository; // 假设依赖 listSetMapper 进行对象转换 @Autowired private ListSetMapper listSetMapper; public void createOrder(OrderDTO dto) { // 需要确保数据库表已存在(依赖 Liquibase) Order entity = listSetMapper.map(dto, Order.class); orderRepository.save(entity); } } ``` --- ### **4. 工作原理** Spring 容器初始化 Bean 的顺序默认按**类路径扫描顺序**或 **@Bean 方法定义顺序**,但可能存在不确定性。 通过 `@DependsOn`,Spring 会构建明确的依赖关系图: ```mermaid graph LR A[Liquibase Bean] --> B[OrderService] C[ListSetMapper Bean] --> B[OrderService] ``` --- ### **5. 注意事项** 1. **Bean 名称匹配**: - `"liquibase"` 和 `"listSetMapper"` 必须是被依赖 Bean 在容器中的**注册名称**(默认类名首字母小写,或通过 `@Component("name")` 自定义)。 - 可通过 `@Bean(name = "customName")` 或 XML 配置指定名称。 2. **循环依赖风险**: 如果 `liquibase` 或 `listSetMapper` 反过来也依赖当前 Bean,会导致启动失败: ```java // 错误示例:循环依赖 @Component @DependsOn("orderService") public class LiquibaseConfig { /*...*/ } ``` 3. **替代方案**: - 通过构造函数注入隐式建立依赖Spring 会按注入顺序自动处理): ```java @Component public class OrderService { // 构造函数注入隐式声明依赖 public OrderService(Liquibase liquibase, ListSetMapper mapper) { /*...*/ } } ``` -- ### **6. 调试技巧** 如果发现依赖未生效: 1. 检查 Bean 名称是否匹配(通过 `/actuator/beans` 端点查看所有注册的 Bean 名称)。 2. 在启动日志中搜索 `Creating bean &#39;liquibase&#39;` 和 `Creating bean &#39;listSetMapper&#39;`,确认它们的初始化顺序。 3. 使用 `@Lazy` 注解延迟初始化非关键依赖(减少启动时间)。 --- ### **7. 扩展应用** - **组合依赖**:声明多个依赖项时,Spring 会确保**所有依赖项均初始化完成**后才初始化当前 Bean。 - **多级依赖**:依赖链可以多层传递(如 `A -> B -> C`),Spring 会自动处理整个依赖链的顺序。 --- ### **总结** `@DependsOn({ "liquibase", "listSetMapper" })` 的本质是**显式控制 Bean 的初始化顺序**,适用于以下场景: - 依赖第三方组件(如数据库迁移工具) - 需要确保工具类优先初始化 - 解决隐式依赖顺序不可控的问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

瑟王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值