Java JMS MessageProducer不需要Connection.start,但MessageConsumer需要Connection.start A-问题

Java JMS MessageProducer不需要Connection.start,但MessageConsumer需要Connection.start A-问题,java,jms,activemq,jms-queue,Java,Jms,Activemq,Jms Queue,我知道有一个类似的问题,但在SO中不一样 我试图了解JMS中消息生产者和消息消费者的幕后运作。通过使用ActiveMQ的实现,我编写了一个简单的MessageProducer示例来向队列发送消息,并编写了一个MessageConsumer示例来在本地运行ActiveMQ时使用队列中的消息 需要连接#启动方法向队列发送消息。具体的调试点如下所示Connection#start触发ActiveMQSession#start方法。调用连接#start时会触发此方法。请参阅org.apache.acti

我知道有一个类似的问题,但在SO中不一样

我试图了解JMS中消息生产者消息消费者的幕后运作。通过使用ActiveMQ的实现,我编写了一个简单的MessageProducer示例来向队列发送消息,并编写了一个MessageConsumer示例来在本地运行ActiveMQ时使用队列中的消息

需要连接#启动方法向队列发送消息。具体的调试点如下所示Connection#start触发ActiveMQSession#start方法。调用连接#start时会触发此方法。请参阅
org.apache.activemq.ActiveMQSession#start
上的以下调试点

问题是,消息生产者并不明确需要连接#启动,但消息消费者需要连接。但是,对于这两个示例,我们都需要清除资源(会话连接)。我意识到的是,如果我删除producer上的Connection#start方法,代码将执行,调试点将不会被触发(甚至不会在引擎盖下),并且我会在队列中看到消息。但是,如果我在使用者上删除了连接#start方法,代码将不会执行,这就是问题所在,为什么在MessageProducer中不需要它,而在MessageConsumer中代码成功执行,但需要它?还有为什么我们不使用连接#start作为MessageProducer,即使我们需要关闭连接以刷新资源。好像代码有味道

我看到,开始的字段是一个
原子布尔值
。我不是并发和多线程方面的专家,因此,可能有人可以解释为什么对于MessageProducer,连接启动不是必需的

B-使用ActiveMQ的JMS MessageProducer示例代码 C-使用ActiveMQ的JMS MessageConsumer示例代码 D-配置和Maven依赖 JDK版本是
1.8
,我正在运行
ActiveMQ 5.15.12
,并且对客户端依赖项使用相同的版本

<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-client</artifactId>
    <version>5.15.12</version>
</dependency>

org.apache.activemq
activemq客户端
5.15.12

此处的行为由JMS规范规定。简单地说,
javax.jms.Connection.start()
适用于消费者而不是生产者。它告诉代理开始向与连接相关联的使用者传递消息。报告说:

通常会将连接保持在停止模式,直到安装完成(即,直到创建了所有消息使用者)。此时,客户端调用连接的start方法,消息开始到达连接的使用者。此设置约定最大限度地减少了在客户端仍在进行自身设置时,异步消息传递可能导致的任何客户端混淆

可以立即启动连接,然后再进行设置。执行此操作的客户端必须准备好在设置过程中处理异步消息传递

start()
方法对生产者没有影响。你看到了预期的行为


值得注意的是,如果您使用的是简化的API(它是JMS 2的一部分),那么这种行为会有所不同。如果使用
JMSContext
创建
JMSConsumer
,则消息传递将自动开始。要明确的是,ActiveMQ 5.x没有实现JMS 2,但是实现了。

您的问题的措辞有点混乱。您会说,“向队列发送消息需要连接启动方法”,以及“MessageProducer上需要连接启动,但MessageConsumer上不需要连接启动。”但是,您也会说,“…如果我删除消费者上的连接#start方法,代码将不会执行,这就是问题所在,为什么MessageProducer中不需要它,而代码成功执行,但MessageConsumer上需要它。“你似乎自相矛盾<代码>连接#开始实际上不需要向队列发送消息。@贾斯汀·伯特伦你是对的,我错误地编写并更新了那个令人困惑的句子。它只在消费者上明确需要,而在生产者上不需要。是的,但是如果不需要使用连接#start,它如何在生产者上启动连接?要发送消息,我们需要MessageProducer,我们需要一个会话实例来创建它,它依赖于连接。这不是有点奇怪吗?因为在我们发送消息之后,我们需要关闭连接,但是,在内部字段中,started没有设置为“true”值。我接受了这个答案,因为它在文档中。但我脑子里仍然有一个问号,为什么会这样,这背后的建筑原因是什么。真奇怪,在一个连接中,我们停止了一些我们没有称之为开始的东西。我将深入探讨它,但是,我希望有一个内部私有字段,我可以跟踪/跟踪连接的状态。这就是为什么乍一看我觉得很奇怪。“启动”连接只是意味着代理应该开始消息传递。这对制作人来说是不必要的。一旦创建了生产者,它就可以开始发送消息。JavaDoc解释了
start()
方法存在的原因。我看不出有什么奇怪的。为什么在发送消息后需要关闭连接?不要在实施中陷入困境。JMS是一种API规范。API的每个实现都是不同的。
package com.bzdgn.jms.stackoverflow;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.activemq.ActiveMQConnectionFactory;

public class JMSConsumeMessageFromQueue {
    
    private static final String ACTIVE_MQ_URL = "tcp://localhost:61616";

    public static void main(String[] args) throws JMSException {
        String queueName = "test_queue";
        
        // Connection Factory from ActiveMQ Implementation
        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(ACTIVE_MQ_URL);
        
        // Get connection from Connection Factory
        Connection connection = connectionFactory.createConnection();
        
        // Create session
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        
        // Consume Message from the Queue
        Queue queue = session.createQueue(queueName);
        MessageConsumer messageConsumer = session.createConsumer(queue);
        
        connection.start();
        
        Message message = messageConsumer.receive(500);
        
        if ( message != null ) {
            if ( message instanceof TextMessage ) {
                TextMessage textMessage = (TextMessage) message;
                String messageContent = textMessage.getText();
                System.out.println("Message Content: " + messageContent);
            }
        } else {
            System.out.println("No message in the queue: " + queueName);
        }
        
        // Clear resources
        session.close();
        connection.close();
    }
    
}
<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-client</artifactId>
    <version>5.15.12</version>
</dependency>