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

ipo*_*voy 2 java jms javalite activemq-artemis

我正在迁移JavaLite 异步从 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();
        }
    }
}

Run Code Online (Sandbox Code Playgroud)

这些行没有任何作用:

CoreQueueConfiguration coreQueueConfiguration = new CoreQueueConfiguration();
coreQueueConfiguration.setName("Queue123").setDurable(true);
configuration.addQueueConfiguration(coreQueueConfiguration);
Run Code Online (Sandbox Code Playgroud)

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

jndi.put("queue.queue/Queue123", "Queue123");
Run Code Online (Sandbox Code Playgroud)

那么 JNDI 找不到队列。

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

jndi.put("queue.queue/Queue123", "Queue123");
Run Code Online (Sandbox Code Playgroud)

然而,这只能部分起作用,队列似乎存在来发送和接收消息,而既不存在也不QueueControl存在QueueBrtowser它。

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

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

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

非常感谢任何帮助!

Jus*_*ram 6

这里似乎存在一些误解......

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

WARN  [org.apache.activemq.artemis.core.server] AMQ222275: Failed to deploy queue <queue name>: null
Run Code Online (Sandbox Code Playgroud)

正如JMS 到核心映射文档中所述,JMS 队列是一个核心地址和一个同名的任播核心队列。因此,您应该使用这样的配置:

WARN  [org.apache.activemq.artemis.core.server] AMQ222275: Failed to deploy queue <queue name>: null
Run Code Online (Sandbox Code Playgroud)

我的猜测是,事情部分正常,因为默认情况下,核心 JMS 客户端将自动创建它需要的目标,因此无论您指定什么,您在 JNDI 属性中配置的任何内容都将自动创建CoreQueueConfiguration。如果您不想自动创建 JMS 目标所需的底层地址和队列,那么您应该使用相应的地址设置来禁用它。还有一些设置可以在不再使用地址和队列时自动删除它们(即当消息计数 = 0 且消费者计数 = 0 时),您可能也想禁用它们。这是一个例子:

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

其次,JNDI 配置在这段文档中进行了解释:

JMS 目标通常也通过 JNDI 查找。与连接工厂一样,可以使用 JNDI 上下文环境中的特殊属性来配置目标。属性名称应遵循以下模式:queue.<jndi-binding>topic.<jndi-binding>。属性应该是 Apache ActiveMQ Artemis 服务器托管的队列的名称。

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

server.getAddressSettingsRepository().addMatch("#", new AddressSettings()
   .setAutoCreateQueues(false)
   .setAutoDeleteQueues(false)
   .setAutoCreateAddresses(false)
   .setAutoDeleteAddresses(false));
Run Code Online (Sandbox Code Playgroud)

该文档还指出:

还可以查找尚未在 JNDI 上下文环境中显式配置的 JMS 目标。这可以在查找字符串中使用dynamicQueues/或。dynamicTopics/例如,如果客户端想要查找上述“OrderQueue”,它可以简单地通过使用字符串“dynamicQueues/OrderQueue”来完成。dynamicQueues/请注意,后面的文本dynamicTopics/必须与服务器上的目标名称完全对应。

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

jndi.put("queue.queue/Queue123", "Queue123");
Run Code Online (Sandbox Code Playgroud)

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

Queue jmsQueue = (Queue) initialContext.lookup("dynamicQueues/Queue123");
Run Code Online (Sandbox Code Playgroud)

要获得队列的控制权,请使用如下命令:

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

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

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