欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-08-29 14:42:29
spring容器载入bean顺序是不确定的,spring框架没有约定特定顺序逻辑规范。但spring保证如果a依赖b(如beana中有@autowired b的变量),那么b将先于a被加载。但如果be...

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。

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