Spring - @DependsOn 控制 Bean 加载顺序

简介: Spring - @DependsOn 控制 Bean 加载顺序

Spring容器载入bean顺序是不确定的,Spring框架没有约定特定顺序逻辑规范。但spring保证如果A依赖B(如beanA中有@Autowired B的变量),那么B将先于A被加载。但如果beanA不直接依赖B,我们如何让B仍先加载呢?

控制 Bean 初始化顺序

可能有些场景中,bean A 间接依赖 bean B。如Bean B应该需要更新一些全局缓存,可能通过单例模式实现且没有在spring容器注册,bean A需要使用该缓存;因此,如果bean B没有准备好,bean A无法访问。

另一个场景中,bean A是事件发布者(或JMS发布者),bean B (或一些) 负责监听这些事件,典型的如观察者模式。我们不想B 错过任何事件,那么B需要首先被初始化。

简言之,有很多场景需要bean B应该被先于bean A被初始化,从而避免各种负面影响。我们可以在bean A上使用@DependsOn注解,告诉容器bean B应该先被初始化。下面通过示例来说明。

示例说明

示例通过事件机制说明,发布者和监听者,然后通过spring配置运行。为了方便说明,示例进行了简化。

EventManager.java

事件管理类,维护监听器列表,通过单例方法获取事件管理器,可以增加监听器或发布事件。


import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class EventManager {
    private final List<Consumer<String>> listeners = new ArrayList<>();
    private EventManager() {
    }
    private static class SingletonHolder {
        private static final EventManager INSTANCE = new EventManager();
    }
    public static EventManager getInstance() {
        return SingletonHolder.INSTANCE;
    }
    public void publish(final String message) {
        listeners.forEach(l -> l.accept(message));
    }
    public void addListener(Consumer<String> eventConsumer) {
        listeners.add(eventConsumer);
    }
}

EventPublisherBean.java

事件发布类,通过EventManager类发布事件。

import com.logicbig.example.EventManager;
public class EventPublisherBean {
    public void initialize() {
        System.out.println("EventPublisherBean initializing");
        EventManager.getInstance().publish("event published from EventPublisherBean");
    }
}

EventListenerBean.java

事件监听者,可以增加监听器。

import com.logicbig.example.EventManager;
public class EventListenerBean {
    private void initialize() {
        System.out.println("EventListenerBean initializing");
        EventManager.getInstance().
                addListener(s ->
                        System.out.println("event received in EventListenerBean : " + s));
    }
}

AppConfig.java

配置运行类。

@Configuration
@ComponentScan("com.logicbig.example")
public class AppConfig {
    @Bean(initMethod = "initialize")
    @DependsOn("eventListener")
    public EventPublisherBean eventPublisherBean () {
        return new EventPublisherBean();
    }
    @Bean(name = "eventListener", initMethod = "initialize")
    // @Lazy
    public EventListenerBean eventListenerBean () {
        return new EventListenerBean();
    }
    public static void main (String... strings) {
        new AnnotationConfigApplicationContext(AppConfig.class);
    }
}

运行AppConfig的main方法,输出结果为

EventListenerBean initializing
EventPublisherBean initializing
event received in EventListenerBean : event published from EventPublisherBean

总结

如果我们注释掉@DependsOn("eventListener"),我们可能不确定获得相同结果。尝试多次运行main方法,偶尔我们将看到EventListenerBean 没有收到事件。为什么是偶尔呢?因为容器启动过程中,spring按任意顺序加载bean。

那么当不使用@DependsOn可以让其100%确定吗?可以使用@Lazy注解放在eventListenerBean ()上。因为EventListenerBean在启动阶段不加载,当其他bean需要其时才加载。这次我们仅EventPublisherBean被初始化。


EventPublisherBean initializing

现在从新增加@DependsOn,也不删除@Lazy注解,输出结果和第一次一致,虽然我们使用了@Lazy注解,eventListenerBean在启动时仍然被加载,因为@DependsOn表明需要EventListenerBean。

目录
相关文章
|
3月前
|
XML Java 数据格式
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
这篇文章是Spring5框架的实战教程,主要介绍了如何在Spring的IOC容器中通过XML配置方式使用外部属性文件来管理Bean,特别是数据库连接池的配置。文章详细讲解了创建属性文件、引入属性文件到Spring配置、以及如何使用属性占位符来引用属性文件中的值。
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
|
10天前
|
缓存 Java Spring
实战指南:四种调整 Spring Bean 初始化顺序的方案
本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析: 1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。 2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。 3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。
实战指南:四种调整 Spring Bean 初始化顺序的方案
|
1月前
|
XML Java 数据格式
Spring从入门到入土(bean的一些子标签及注解的使用)
本文详细介绍了Spring框架中Bean的创建和使用,包括使用XML配置文件中的标签和注解来创建和管理Bean,以及如何通过构造器、Setter方法和属性注入来配置Bean。
66 9
Spring从入门到入土(bean的一些子标签及注解的使用)
|
2月前
|
缓存 安全 Java
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
从底层源码入手,通过代码示例,追踪AnnotationConfigApplicationContext加载配置类、启动Spring容器的整个流程,并对IOC、BeanDefinition、PostProcesser等相关概念进行解释
203 24
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
|
29天前
|
Java 测试技术 Windows
咦!Spring容器里为什么没有我需要的Bean?
【10月更文挑战第11天】项目经理给小菜分配了一个紧急需求,小菜迅速搭建了一个SpringBoot项目并完成了开发。然而,启动测试时发现接口404,原因是控制器包不在默认扫描路径下。通过配置`@ComponentScan`的`basePackages`字段,解决了问题。总结:`@SpringBootApplication`默认只扫描当前包下的组件,需要扫描其他包时需配置`@ComponentScan`。
|
2月前
|
XML Java 数据格式
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
Spring 第二节内容补充 关于Bean配置的更多内容和细节 万字详解!
210 18
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
|
2月前
|
XML Java 数据格式
spring复习02,xml配置管理bean
详细讲解了Spring框架中基于XML配置文件管理bean的各种方式,包括获取bean、依赖注入、特殊值处理、属性赋值、集合类型处理、p命名空间、bean作用域及生命周期和自动装配。
spring复习02,xml配置管理bean
|
1月前
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细解析Spring Bean的生命周期及其核心概念,并深入源码分析。Spring Bean是Spring框架的核心,由容器管理其生命周期。从实例化到销毁,共经历十个阶段,包括属性赋值、接口回调、初始化及销毁等。通过剖析`BeanFactory`、`ApplicationContext`等关键接口与类,帮助你深入了解Spring Bean的管理机制。希望本文能助你更好地掌握Spring Bean生命周期。
73 1
|
1月前
|
Java Spring
获取spring工厂中bean对象的两种方式
获取spring工厂中bean对象的两种方式
37 1
|
1月前
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细介绍了Spring框架中的核心概念——Spring Bean的生命周期,包括实例化、属性赋值、接口回调、初始化、使用及销毁等10个阶段,并深入剖析了相关源码,如`BeanFactory`、`DefaultListableBeanFactory`和`BeanPostProcessor`等关键类与接口。通过理解这些核心组件,读者可以更好地掌握Spring Bean的管理和控制机制。
84 1