You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

跨子模块通信实现咨询:回调/监听器及广播方案示例

嘿,这个问题问得很实在!跨子模块通信在Java项目里完全可行,回调/监听器是最常用的方案之一,广播也能轻松实现,下面我给你一步步拆解并附上可运行的代码示例。

一、用回调/监听器实现跨子模块通信(最推荐的方案)

这种方式的核心是定义一个公共接口让两个模块对接,只要模块之间有合理的依赖关系(比如A依赖B,或者双方依赖同一个公共API模块),就能顺畅通信。

1. 先定义回调接口

首先得有一个双方都能访问到的回调接口——最好放在公共的API包下(比如你有父模块的话就放父模块的api目录,要是是单向依赖,比如submodule2依赖submodule1,那就把接口放在submodule1里)。

// 示例:放在submodule1的com.example.api包下
public interface SecretCallback {
    // 定义回调方法,参数根据你的业务需求调整
    void onSecretDataReceived(String secretData);
}

2. 在SecretService里添加回调注册和触发逻辑

修改submodule1里的SecretService,让它能接收外部注册的回调,并且在数据就绪时通知所有注册的对象:

package com.example.submodule1.service;

import com.example.api.SecretCallback;
import java.util.ArrayList;
import java.util.List;

public class SecretService {
    // 用列表存所有注册的回调,支持一对多通知
    private final List<SecretCallback> callbacks = new ArrayList<>();

    // 注册回调的方法
    public void registerCallback(SecretCallback callback) {
        if (!callbacks.contains(callback)) {
            callbacks.add(callback);
        }
    }

    // 别忘了加取消注册的方法,避免内存泄漏!
    public void unregisterCallback(SecretCallback callback) {
        callbacks.remove(callback);
    }

    // 模拟获取秘密数据的业务方法,拿到数据后触发回调
    public void fetchSecretData() {
        // 这里替换成你的实际业务逻辑:比如从DB/外部接口拿数据
        String secretData = "Top Secret: 12345";
        
        // 遍历所有回调,通知数据更新
        for (SecretCallback callback : callbacks) {
            callback.onSecretDataReceived(secretData);
        }
    }
}

3. 在AwesomeManager里实现回调并注册

在submodule2的AwesomeManager中,实现刚才的回调接口,然后把自己注册到SecretService里:

package com.example.submodule2.manager;

import com.example.api.SecretCallback;
import com.example.submodule1.service.SecretService;

public class AwesomeManager implements SecretCallback {

    // 构造方法里完成注册,也可以单独写个init方法
    public AwesomeManager(SecretService secretService) {
        secretService.registerCallback(this);
    }

    @Override
    public void onSecretDataReceived(String secretData) {
        // 这里写你收到数据后的业务逻辑
        System.out.println("AwesomeManager 收到秘密数据:" + secretData);
        // 比如更新缓存、触发UI刷新、调用其他服务等等
    }
}

4. 测试一下

写个启动类验证效果:

public class MainApp {
    public static void main(String[] args) {
        SecretService secretService = new SecretService();
        AwesomeManager awesomeManager = new AwesomeManager(secretService);
        
        // 触发SecretService获取数据,此时AwesomeManager会收到回调
        secretService.fetchSecretData();
    }
}

注意事项

  • 依赖配置:要确保submodule2能访问到SecretService和SecretCallback,比如在submodule2的pom.xml里加submodule1的依赖。
  • 内存泄漏:当AwesomeManager不再需要时,一定要调用unregisterCallback,不然SecretService会一直持有它的引用,导致内存泄漏。
二、用广播(事件总线)实现跨子模块通信

如果你的场景是一对多、多对多,或者不想让模块之间有直接依赖,广播/事件总线是更好的选择。这里给你两种实现方式:自己写简单的广播器,或者用成熟的框架(比如Guava EventBus)。

方式1:自己实现简单广播机制

1. 定义事件类

先在公共API包下定义一个事件类,用来传递数据:

public class SecretEvent {
    private final String secretData;

    public SecretEvent(String secretData) {
        this.secretData = secretData;
    }

    // 提供 getter 让订阅者拿数据
    public String getSecretData() {
        return secretData;
    }
}

2. 实现事件总线(广播器)

写一个单例的事件总线,用来管理订阅者和发布事件:

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

public class EventBus {
    // 单例模式,全局唯一
    private static final EventBus INSTANCE = new EventBus();
    // 存储SecretEvent的订阅者
    private final List<Consumer<SecretEvent>> secretEventListeners = new ArrayList<>();

    private EventBus() {}

    public static EventBus getInstance() {
        return INSTANCE;
    }

    // 注册订阅者
    public void registerSecretEventListener(Consumer<SecretEvent> listener) {
        if (!secretEventListeners.contains(listener)) {
            secretEventListeners.add(listener);
        }
    }

    // 取消订阅
    public void unregisterSecretEventListener(Consumer<SecretEvent> listener) {
        secretEventListeners.remove(listener);
    }

    // 发布事件,通知所有订阅者
    public void publishSecretEvent(SecretEvent event) {
        for (Consumer<SecretEvent> listener : secretEventListeners) {
            listener.accept(event);
        }
    }
}

3. SecretService发布事件

修改SecretService,当数据就绪时发布事件:

package com.example.submodule1.service;

import com.example.api.EventBus;
import com.example.api.SecretEvent;

public class SecretService {
    public void fetchSecretData() {
        String secretData = "Top Secret: 67890";
        // 发布事件
        EventBus.getInstance().publishSecretEvent(new SecretEvent(secretData));
    }
}

4. AwesomeManager订阅事件

在AwesomeManager里订阅事件,处理数据:

package com.example.submodule2.manager;

import com.example.api.EventBus;
import com.example.api.SecretEvent;

public class AwesomeManager {
    public AwesomeManager() {
        // 订阅SecretEvent,用Lambda表达式处理事件
        EventBus.getInstance().registerSecretEventListener(event -> {
            System.out.println("AwesomeManager 通过广播收到秘密数据:" + event.getSecretData());
            // 这里写业务逻辑
        });
    }
}

方式2:用Guava EventBus(更简洁)

如果项目里已经用了Guava,直接用它的EventBus会省很多事,代码更简洁:

1. 添加Guava依赖(Maven示例)

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>32.1.3-jre</version>
</dependency>

2. SecretService发布事件

package com.example.submodule1.service;

import com.google.common.eventbus.EventBus;

public class SecretService {
    private final EventBus eventBus;

    public SecretService(EventBus eventBus) {
        this.eventBus = eventBus;
    }

    public void fetchSecretData() {
        String secretData = "Top Secret: Guava EventBus";
        // 发布事件
        eventBus.post(new SecretEvent(secretData));
    }
}

3. AwesomeManager订阅事件

用@Subscribe注解标记订阅方法,非常方便:

package com.example.submodule2.manager;

import com.google.common.eventbus.Subscribe;

public class AwesomeManager {
    public AwesomeManager(EventBus eventBus) {
        // 注册自己到EventBus
        eventBus.register(this);
    }

    // 用@Subscribe注解标记订阅方法,参数是要监听的事件类
    @Subscribe
    public void onSecretEventReceived(SecretEvent event) {
        System.out.println("AwesomeManager 通过Guava EventBus收到数据:" + event.getSecretData());
    }
}

4. 测试示例

import com.google.common.eventbus.EventBus;

public class MainApp {
    public static void main(String[] args) {
        EventBus eventBus = new EventBus();
        SecretService secretService = new SecretService(eventBus);
        AwesomeManager awesomeManager = new AwesomeManager(eventBus);
        
        secretService.fetchSecretData();
    }
}
最后捋捋
  • 回调/监听器:适合一对一或者少量一对多的场景,模块之间依赖关系明确,实现简单直接,性能也不错。
  • 广播/事件总线:适合一对多、多对多的场景,模块之间解耦性更高,用成熟框架的话开发效率拉满。

两种方案都完全可行,选哪个就看你的业务场景和模块依赖设计啦~

内容的提问来源于stack exchange,提问作者MaaAn13

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:01:03