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

Wildfly 11独立模式下跨实例同主题JMS消息收发实现问询

实现Wildfly 11独立集群实例间的跨实例JMS主题消息收发

嘿,我来帮你搞定这个跨实例JMS消息收发的需求!结合你给出的Receiver代码片段,我整理了完整的实现步骤,从集群配置到代码完善,再到测试验证,一步一步来:

一、先搞定Wildfly集群基础配置

你已经用standalone-full-ha.xml启动实例了,这个配置文件默认已经开启了集群相关的功能,但得确保两个实例能互相发现并组成集群:

  • 启动第一个实例(node1):
    ./standalone.sh -c standalone-full-ha.xml -Djboss.node.name=node1 -Djboss.socket.binding.port-offset=0
    
  • 启动第二个实例(node2):
    ./standalone.sh -c standalone-full-ha.xml -Djboss.node.name=node2 -Djboss.socket.binding.port-offset=100
    

这里用端口偏移避免两个实例的端口冲突,节点名称要唯一,启动后可以看日志,出现Joined cluster的字样就说明集群组建成功了。

接下来要确保主题topic/Blubb在两个实例中都能访问到,用Wildfly的CLI工具连接到任意一个实例,执行以下命令创建可跨实例访问的主题:

/subsystem=messaging-activemq/server=default/jms-topic=Blubb:add(entries=["java:/jms/topic/Blubb", "java:jboss/exported/jms/topic/Blubb"])

这个命令会创建两个JNDI入口,其中java:jboss/exported开头的是对外暴露的,方便跨实例访问。

二、完善你的Receiver(Message-Driven Bean)

你给出的Receiver代码已经有了基础框架,我帮你补全并加上集群相关的关键配置:

import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.inject.Named;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

@Named
@MessageDriven(
    name = "TaskJmsMsgReceiver",
    activationConfig = {
        @ActivationConfigProperty(
            propertyName = "destinationLookup",
            propertyValue = "java:jboss/exported/jms/topic/Blubb"
        ),
        @ActivationConfigProperty(
            propertyName = "destinationType",
            propertyValue = "javax.jms.Topic"
        ),
        @ActivationConfigProperty(
            propertyName = "acknowledgeMode",
            propertyValue = "Auto-acknowledge"
        ),
        // 集群环境下必须加这个,让MDB能参与集群消费
        @ActivationConfigProperty(
            propertyName = "cluster",
            propertyValue = "true"
        )
    }
)
public class TaskJmsMsgReceiver implements MessageListener {

    @Override
    public void onMessage(Message message) {
        if (message instanceof TextMessage) {
            try {
                String msgContent = ((TextMessage) message).getText();
                // 打印当前节点名称,方便验证是哪个实例收到了消息
                System.out.println("Receiver on node " + System.getProperty("jboss.node.name") + " got message: " + msgContent);
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    }
}

几个关键点要注意:

  • 用java:jboss/exported/jms/topic/Blubb作为目标查找路径,这样另一个实例的Sender才能找到这个主题
  • cluster=true的配置是核心,确保这个MDB能在集群环境下接收消息,毕竟主题是发布订阅模式,两个实例的Receiver都应该收到消息
  • 打印节点名称是为了直观看到跨实例的效果

三、实现Sender组件(JMS Producer)

Sender可以做成一个CDI bean或者无状态EJB,我这里用CDI bean的方式,方便你和Receiver一起打包部署:

import javax.annotation.Resource;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;

@Named
@RequestScoped
public class TaskJmsMsgSender {

    // 注入Wildfly默认的集群化连接工厂,支持跨实例通信
    @Resource(mappedName = "java:/ConnectionFactory")
    private ConnectionFactory connectionFactory;

    // 注入我们创建的主题
    @Resource(mappedName = "java:jboss/exported/jms/topic/Blubb")
    private Topic blubbTopic;

    public void sendMessage(String messageContent) {
        // 用try-with-resources自动关闭JMS资源,避免泄漏
        try (Connection connection = connectionFactory.createConnection();
             Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
             MessageProducer producer = session.createProducer(blubbTopic)) {

            TextMessage message = session.createTextMessage(messageContent);
            producer.send(message);
            System.out.println("Sender on node " + System.getProperty("jboss.node.name") + " sent message: " + messageContent);

        } catch (JMSException e) {
            e.printStackTrace();
        }
    }
}

这里的核心是用Wildfly默认的集群化连接工厂java:/ConnectionFactory,它已经配置好了跨实例的通信支持,不用额外折腾。

四、部署和测试

  1. 把Sender、Receiver和测试用的端点(如果需要)打包成WAR或者EAR包,分别部署到两个Wildfly实例上
  2. 我给你写个简单的REST端点来调用Sender,方便测试:
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;

@Path("/jms-test")
public class JmsTestEndpoint {

    @Inject
    private TaskJmsMsgSender sender;

    @GET
    @Path("/send")
    public String sendTestMessage(@QueryParam("content") String content) {
        sender.sendMessage(content);
        return "Message sent successfully: " + content;
    }
}
  1. 调用这个接口,比如访问http://localhost:8080/your-app-name/jms-test/send?content=Hello Wildfly Cluster!,然后去两个实例的控制台看日志——你会看到两个Receiver都打印出收到的消息,这就说明跨实例的主题消息收发成功了!

五、一些踩坑提示

  • 要是集群组建失败,检查两个实例的网络是否互通,或者看看Wildfly的集群配置(standalone-full-ha.xml里的subsystem=jgroups部分)有没有问题
  • 如果主题找不到,确认你用CLI创建主题的命令执行成功了,或者直接在standalone-full-ha.xml里手动添加主题配置
  • 集群环境下的消息可靠性:Wildfly的ActiveMQ Artemis集群默认支持消息复制,你可以测试关闭一个实例,发送消息后再重启,看看重启后的实例能不能收到消息,确保消息不会丢失

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:07:18