SpringBoot中EngineListener子类实例如何注入空List?GitBitex代码疑问
List<EngineListener>实例注入的原理 我正在学习Java和SpringBoot,在开源仓库的Bootstrap.java类中发现一处特殊代码:
private final ModifiedObjectWriter modifiedObjectWriter; private final EngineSnapshotTaker engineSnapshotTaker; private final OrderBookSnapshotTaker orderBookSnapshotTaker; private final List<EngineListener> engineListeners; @PostConstruct public void init() { startMatchingEngine(1); startOrderPersistenceThread(1); startTradePersistenceThread(1); startAccountPersistenceThread(1); startCandleMaker(1); startTickerThread(1); } private void startMatchingEngine(int nThreads) { for (int i = 0; i < nThreads; i++) { String groupId = "MatchingEngine"; KafkaConsumer<String, Command> consumer = new KafkaConsumer<>(getProperties(groupId), new StringDeserializer(), new CommandDeserializer()); MatchingEngineThread matchingEngineThread = new MatchingEngineThread(consumer, engineSnapshotStore, engineListeners, appProperties); matchingEngineThread.setName(groupId + "-" + matchingEngineThread.getId()); matchingEngineThread.start(); threads.add(matchingEngineThread); } }
我的观察:
- 前三个类
ModifiedObjectWriter、EngineSnapshotTaker、OrderBookSnapshotTaker均继承自EngineListener类,但未被显式调用; engineListeners被使用,但代码中看起来是空List;ModifiedObjectWriter标注了@Component注解;- 运行时发现
engineListenersList中包含这三个类的实例。
想知道这些类的实例是如何注入到engineListeners List中的?
这是Spring框架的集合自动注入特性结合项目配置共同作用的结果,具体逻辑如下:
Spring对Bean的扫描与实例化
项目中ModifiedObjectWriter标注了@Component,而EngineSnapshotTaker、OrderBookSnapshotTaker也都带有@Component注解。Spring启动时会扫描所有标注了@Component(或@Service、@Repository等 stereotype 注解)的类,将它们实例化为Bean并纳入Spring容器管理。基于父类型的集合自动注入
Spring支持自动将容器中所有类型为指定父类/接口的Bean,注入到对应的集合中。这里engineListeners的类型是List<EngineListener>,而三个类都继承自EngineListener,因此Spring会自动把这三个Bean收集起来,注入到engineListeners这个List中。构造注入的隐式生效
Bootstrap类本身是Spring管理的Bean(标注了@Component或@Configuration),且只有一个构造函数。Spring 4.3+版本之后,对于只有单个构造函数的类,会自动进行构造注入,无需额外添加@Autowired注解——engineListeners就是通过构造函数被注入的。隐式调用的逻辑
三个类作为EngineListener的实现,不需要在Bootstrap中显式调用。它们的逻辑会通过观察者模式触发:MatchingEngineThread内部会在撮合引擎产生事件(如订单更新、交易完成)时,遍历engineListeners并调用对应的回调方法(比如onOrderUpdated、onTrade),从而触发三个类的业务逻辑。
内容的提问来源于stack exchange,提问作者Ramesh Pareek

