使用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。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。