java - 如何在代码中创建 Apache Artemis 队列并将它们与 JMS 一起使用?

标签 java jms activemq-artemis javalite

我正在迁移 JavaLite Async从 Artemis 2.3.0 到 2.11.0 版本。 JavaLite Async 不使用任何文件基础配置,而是依赖于代码。

在 v 2.3.0 和 2.11.0 之间,JMS 管理 API 现已消失/弃用,我们鼓励使用核心管理 API。

不幸的是我找不到办法:

  1. 以编程方式创建队列
  2. 使用 JNDI 查找队列以使用 JMS 发送和接收消息。

这是一个示例(为简洁起见,保留导入):

class QueueLookup {
    private static final String LOCATION = "./target/artemis";

    private static EmbeddedActiveMQ server;

    public static void main(String[] args) throws Exception {
        try{
            Configuration configuration = new ConfigurationImpl()
                    .setPersistenceEnabled(true)
                    .setBindingsDirectory(LOCATION + "/bindings")
                    .setJournalDirectory(LOCATION + "/journal")
                    .setLargeMessagesDirectory(LOCATION + "/largemessages")
                    .setPagingDirectory(LOCATION + "/paging")
                    .setSecurityEnabled(false)
                    .addAcceptorConfiguration("invm", "vm://0")
                    .setJournalBufferTimeout_AIO(100)
                    .setJournalBufferTimeout_NIO(100)
                    .setJournalType(JournalType.NIO)
                    .setMaxDiskUsage(90);


            //the following three lines have no effect
            CoreQueueConfiguration coreQueueConfiguration = new CoreQueueConfiguration();
            coreQueueConfiguration.setName("Queue123").setDurable(true);
            configuration.addQueueConfiguration(coreQueueConfiguration);


            server = new EmbeddedActiveMQ();
            server.setConfiguration(configuration);
            server.start();


            TransportConfiguration transportConfiguration = new TransportConfiguration(InVMConnectorFactory.class.getName());
            ConnectionFactory connectionFactory = ActiveMQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, transportConfiguration);

            Hashtable<String, String> jndi = new Hashtable<>();
            jndi.put("java.naming.factory.initial", "org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory");
            jndi.put("connectionFactory.ConnectionFactory", "vm://0");
            //# queue.[jndiName] = [physicalName]
            jndi.put("queue.queue/Queue123", "Queue123");

            InitialContext initialContext = new InitialContext(jndi);
            Queue jmsQueue = (Queue) initialContext.lookup("queue/Queue123");

            try (Connection connection = connectionFactory.createConnection()) {
                try(Session jmsSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE)){
                    MessageProducer producer = jmsSession.createProducer(jmsQueue);
                    connection.start();
                    TextMessage message = jmsSession.createTextMessage("Hello, Artemis!");
                    producer.send(message);
                    System.out.println("Message sent: " + message.getText());
                }
            } catch (Exception ex){
                ex.printStackTrace();
            }

        }finally {
            server.stop();
        }
    }
}

这些行没有效果:

CoreQueueConfiguration coreQueueConfiguration = new CoreQueueConfiguration();
coreQueueConfiguration.setName("Queue123").setDurable(true);
configuration.addQueueConfiguration(coreQueueConfiguration);

但是,如果我删除这一行:

jndi.put("queue.queue/Queue123", "Queue123");

然后 JNDI 找不到队列。

从表面上看,我似乎可以通过将队列的名称添加到 JNDI 来“创建”队列:

jndi.put("queue.queue/Queue123", "Queue123");

然而,这只能部分起作用,队列似乎存在于 发送和接收消息,而 QueueControlQueueBrtowser 都找不到它。

谁能解释一下我如何在代码中做到这一点(没有 XML 配置):

  1. 创建一个队列并传递所有必要的参数(持久等)
  2. 使用 JNDI 找到这个队列
  3. 使用 QueueControl 控制这个队列
  4. 使用 QueueBrowser 浏览此队列。

可以在此处找到带有 GUI 版本的完整示例:https://github.com/ipolevoy/artemis-sanbox/blob/master/src/main/java/examples/

非常感谢任何帮助!

最佳答案

这里似乎有一些误解......

首先,你的原因 CoreQueueConfiguration “无效”是因为它无效。它无效,因为您没有指定队列将绑定(bind)到的地址的名称。当代理出现表明配置无效时,它应该记录如下内容:

WARN  [org.apache.activemq.artemis.core.server] AMQ222275: Failed to deploy queue <queue name>: null

JMS-to-core mapping documentation 中所述,一个JMS队列是一个核心地址和一个同名的anycast核心队列。因此,您应该改用这样的配置:

coreQueueConfiguration.setAddress("Queue123").setName("Queue123").setDurable(true).setRoutingType(org.apache.activemq.artemis.api.core.RoutingType.ANYCAST);

我的猜测是部分工作正常,因为默认情况下核心 JMS 客户端将自动创建它需要的目的地,因此无论 CoreQueueConfiguration 是什么,无论您在 JNDI 属性中配置什么,都会自动创建。你已经指定了。如果您不想自动创建 JMS 目标所需的底层地址和队列,那么您应该使用相应的地址设置禁用它。还有一些设置可以在不再使用地址和队列时自动删除它们(即当 message-count = 0 和 counsumer-count = 0 时),您可能也想禁用这些设置。这是一个例子:

server.getAddressSettingsRepository().addMatch("#", new AddressSettings()
   .setAutoCreateQueues(false)
   .setAutoDeleteQueues(false)
   .setAutoCreateAddresses(false)
   .setAutoDeleteAddresses(false));

其次,JNDI 配置在this bit of documentation 中解释。 :

JMS destinations are also typically looked up via JNDI. As with connection factories, destinations can be configured using special properties in the JNDI context environment. The property name should follow the pattern: queue.<jndi-binding> or topic.<jndi-binding>. The property value should be the name of the queue hosted by the Apache ActiveMQ Artemis server.

这解释了为什么需要这一行:

jndi.put("queue.queue/Queue123", "Queue123");

The documentation还指出:

It is also possible to look-up JMS destinations which haven't been configured explicitly in the JNDI context environment. This is possible using dynamicQueues/ or dynamicTopics/ in the look-up string. For example, if the client wanted to look-up the aforementioned "OrderQueue" it could do so simply by using the string "dynamicQueues/OrderQueue". Note, the text that follows dynamicQueues/ or dynamicTopics/ must correspond exactly to the name of the destination on the server.

这意味着您可以省略上述行并改用这种查找:

Queue jmsQueue = (Queue) initialContext.lookup("dynamicQueues/Queue123");

也就是说,不清楚为什么要在这里使用 JNDI 而不是简单地使用 JMS API 实例化目标。您可以通过删除所有 JNDI 代码来显着简化该代码,例如:

ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://0");

try (Connection connection = connectionFactory.createConnection(); 
     Session jmsSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE)) {
   MessageProducer producer = jmsSession.createProducer(jmsSession.createQueue("Queue123"));
   connection.start();
   TextMessage message = jmsSession.createTextMessage("Hello, Artemis!");
   producer.send(message);
   System.out.println("Message sent: " + message.getText());
} catch (Exception ex) {
   ex.printStackTrace();
}

要获得对队列的控制,请使用如下内容:

QueueControl coreQueueControl = (QueueControl) server.getManagementService().getResource(org.apache.activemq.artemis.api.core.management.ResourceNames.QUEUE + "Queue123");

要浏览队列,您可以使用 javax.jms.QueueBrowser .网上有很多这方面的教程。

最后,在我们添加了对 AMQP、MQTT 和 OpenWire 的支持后,我们在 2.0.0 版发布之前决定弃用 JMS 配置和管理位。在这一点上,将配置和管理简化为核心资源(即地址、队列和路由类型)是有意义的。拥有所有核心内容加上相应的 JMS 配置和管理肯定会给用户带来困惑,而且也很难维护。我们花了相当多的时间更新文档来解释一切如何从各种支持的协议(protocol)和 API 映射到核心资源。 This document提供您可能会觉得有用的概述。

关于java - 如何在代码中创建 Apache Artemis 队列并将它们与 JMS 一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60747639/

相关文章:

java - 创建后按指定顺序设置 JTable 的列

c++ - ActiveMQCPP connection.start() 挂了

java - Camel : Write Message to WMQ

java - 如何向 Artemis 添加 JAAS 登录模块?

java - IBM Domino Java - 优化 $(Rooms) View 上特定 Internet 地址的搜索

java - 如何从 wsimport 生成 SoapProxy?

java - 无法将 org.apache.qpid.jms.provider.amqp.AmqpProviderFactory 转换为 org.apache.qpid.jms.provider.ProviderFactory

activemq-artemis - Artemis : AMQ222210: Storage usage is beyond max-disk-usage. 系统将开始阻止生产者

java - dyld : Symbol not found: _JNI_CreateJavaVM

java - jms 消息不移动 websphere 中的队列