使用Spring @DependsOn控制bean加载顺序的实例

 更新时间:2021年07月22日 15:12:13   作者:梦想画家  
这篇文章主要介绍了使用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() {
        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需要其时才加载。这次我们仅EventListenerBean被初始化。

EventPublisherBean initializing

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

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 解决rocketmq-client查询手动发送消息异常问题

    解决rocketmq-client查询手动发送消息异常问题

    这篇文章主要介绍了解决rocketmq-client查询手动发送消息异常问题,具有很好的参考价值,希望对大家大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • Java中Map与JSON数据之间的互相转化

    Java中Map与JSON数据之间的互相转化

    我们在开发中难免和JSON打交道,这不小编最近遇到了,需要把一些信息转成JSON字符串,下面这篇文章主要给大家介绍了关于Java中Map与JSON数据之间的互相转化,需要的朋友可以参考下
    2023-04-04
  • Java多线程连续打印abc实现方法详解

    Java多线程连续打印abc实现方法详解

    这篇文章主要介绍了Java多线程连续打印abc实现方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • IDEA Debug过程中使用Drop Frame或Reset Frame实现操作回退的方法

    IDEA Debug过程中使用Drop Frame或Reset Frame实现操作回退的方法

    在IDEA中就提供了一个帮助你回退代码的机会,但这个方法并不是万能的,好了,下面就来具体说说IDEA Debug过程中使用Drop Frame或Reset Frame实现操作回退的方法,感兴趣的朋友一起看看吧
    2022-04-04
  • Java网络编程三要素及通信程序详解

    Java网络编程三要素及通信程序详解

    这篇文章主要介绍了Java网络编程三要素及通信程序详解,Java网络编程是在网络通信协议下,实现网络互连的不同计算机上运行的程序间可以进行数据交换,需要的朋友可以参考下
    2023-07-07
  • Spring Data Redis切换底层Jedis和Lettuce实现源码解析

    Spring Data Redis切换底层Jedis和Lettuce实现源码解析

    这篇文章主要为大家介绍了Spring Data Redis切换底层Jedis和Lettuce实现方法源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • java实现装饰器模式(Decorator Pattern)

    java实现装饰器模式(Decorator Pattern)

    这篇文章主要为大家详细介绍了java实现装饰器模式Decorator Pattern,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-10-10
  • SpringBoot修改内置tomcat版本的操作步骤

    SpringBoot修改内置tomcat版本的操作步骤

    生产环境使用的外部部署Tomcat还是内置Tomcat由于版本安全漏洞,往往需要升级到指定的安全版本,本文演示一下SpringBoot升级内置的Tomcat版本,感兴趣的小伙伴跟着小编一起来看看吧
    2024-07-07
  • Spring MVC项目中的异常处理详解

    Spring MVC项目中的异常处理详解

    在Web开发中 我们经常会需要处理各种异常,这篇文章主要给大家介绍了关于Spring MVC项目中异常处理的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-06-06
  • Java中notify()和notifyAll()的使用区别

    Java中notify()和notifyAll()的使用区别

    本文主要介绍了Java中notify()和notifyAll()的使用区别,文中通过示例代码介绍的非常详细,感兴趣的小伙伴们可以参考一下
    2021-06-06

最新评论