【问题标题】:How to connect to RabbitMQ using RabbitMQ JMS client from an existing JMS application?如何使用 RabbitMQ JMS 客户端从现有 JMS 应用程序连接到 RabbitMQ?
【发布时间】:2016-01-27 19:55:47
【问题描述】:

我有一个通用的独立 JMS 应用程序,它与以下 JMS 提供程序 WebSphere、HornetQ 和 ActiveMq 一起使用。我将 Context.INITIAL_CONTEXT_FACTORY 和 Context.PROVIDER_URL 作为参数传递给我的应用程序,并通过执行类似的操作从它们中创建命名上下文

Properties environmentParameters = new Properties();
environmentParameters.put(Context.INITIAL_CONTEXT_FACTORY, property.context);
environmentParameters.put(Context.PROVIDER_URL, property.provider);
namingContext = new InitialContext(environmentParameters);

并使用此上下文进行对象查找。

我了解 RabbitMQ 不是 JMS 提供者,因此它没有 InitialContext 类或提供者 URL,但它提供了一个 JMS 客户端,它是符合 JMS 规范的 Java 客户端的抽象。 RabbitMQ 的 JMS 客户端 documentation 有一个将 JNDI 中的对象定义为作为 Web 应用程序的一部分的资源配置的示例,但我完全不知道如何为我的独立应用程序做类似的事情,该应用程序基于 JNDI 提供程序创建命名上下文使用 JMS 客户端的依赖项或从可用的依赖项中创建 InitialContext。

那么有人可以说明如何做到这一点吗?希望我的问题很清楚。

【问题讨论】:

    标签: java jms rabbitmq


    【解决方案1】:

    为了让 JMSRabbitMQ 一起工作,您必须启用 插件 rabbitmq_jms_topic_exchange
    您可以按照本网站的说明下载(您需要登录):
    https://my.vmware.com/web/vmware/details?downloadGroup=VFRMQ_JMS_105&productId=349

    1. 解压后,将文件 rjms-topic-selector-1.0.5.ez 放入文件夹 $RABBITMQ_SERVER\plugins。
    2. 使用以下命令启用插件:rabbitmq-plugins enable rabbitmq_jms_topic_exchange
    3. 使用以下命令检查插件是否运行正常:rabbitmq-plugins list
    4. 重启 RabbitMQ - 我不确定是否真的有必要,但以防万一 ;-)
    5. 在您的 RabbitMQ 网络管理 (http://localhost:15672/#/exchanges) 中,您可以查看可用的新 Exchange:
    6. 现在,理论上 :-),您已经能够使用标准 Java JMS API 连接到您的 RabbiMQ 服务器。

    请记住,您必须创建一个 .bindings 文件才能让 JNDI 找到您注册的对象。这是它的内容示例:

    ConnectionFactory/ClassName=com.rabbitmq.jms.admin.RMQConnectionFactory ConnectionFactory/FactoryName=com.rabbitmq.jms.admin.RMQObjectFactory ConnectionFactory/RefAddr/0/Content=jms/ConnectionFactory ConnectionFactory/RefAddr/0/Type=name ConnectionFactory/RefAddr/0/Encoding=String ConnectionFactory/RefAddr/1/Content=javax.jms.ConnectionFactory ConnectionFactory/RefAddr/1/Type=type ConnectionFactory/RefAddr/1/Encoding=String ConnectionFactory/RefAddr/2/Content=com.rabbitmq.jms.admin.RMQObjectFactory ConnectionFactory/RefAddr/2/Type=factory ConnectionFactory/RefAddr/2/Encoding=String # Change this line accordingly if the broker is not at localhost ConnectionFactory/RefAddr/3/Content=localhost ConnectionFactory/RefAddr/3/Type=host ConnectionFactory/RefAddr/3/Encoding=String # HELLO Queue HELLO/ClassName=com.rabbitmq.jms.admin.RMQDestination HELLO/FactoryName=com.rabbitmq.jms.admin.RMQObjectFactory HELLO/RefAddr/0/Content=jms/Queue HELLO/RefAddr/0/Type=name HELLO/RefAddr/0/Encoding=String HELLO/RefAddr/1/Content=javax.jms.Queue HELLO/RefAddr/1/Type=type HELLO/RefAddr/1/Encoding=String HELLO/RefAddr/2/Content=com.rabbitmq.jms.admin.RMQObjectFactory HELLO/RefAddr/2/Type=factory HELLO/RefAddr/2/Encoding=String HELLO/RefAddr/3/Content=HELLO HELLO/RefAddr/3/Type=destinationName HELLO/RefAddr/3/Encoding=String

    然后……最后……代码:

    属性 environmentParameters = new Properties(); environmentParameters.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory"); environmentParameters.put(Context.PROVIDER_URL, "file:/C:/rabbitmq-bindings"); 命名上下文 = 新的初始上下文(环境参数); ConnectionFactory connFactory = (ConnectionFactory) ctx.lookup("ConnectionFactory");

    【讨论】:

    • 谢谢,关于配置,我做对了,但我不知道如何创建这个 .bindings 文件。我确实遇到了几个例子,但有没有办法创建这个文件?某些系统(如 IBM WMQ)负责为用户创建此文件。
    • 我在没有工具帮助的情况下创建了这个文件。对于 RabbitMQ,我不知道它是否有自动创建的方法,我不这么认为。我根据我在 Internet 上找到的一些读数遵循了语法,并比较了 IBM MQ Explorer 自动创建的 .bindings 文件。
    • 好的,我明白了。甚至令人惊讶的是,除了互联网上的一些帖子外,我没有在这个 .bindings 文件上找到任何官方文档。不管怎样,我会试试你的答案,看看。
    • 我们是否需要显式添加 x-jms-topic 类型的交换?默认情况下,我看不到任何名为 jms.durable.queues 的交换?在您的屏幕截图中,为什么类型是直接的?不应该是 JMS 队列之类的吗?
    • @NiranjanSubramanian 实际上所有这些都是在您安装插件时自动为您设置的,那么除了安装之外您不需要做任何其他事情。
    【解决方案2】:

    对于遇到此异常的人

    Caused by: javax.naming.NamingException: Unknown class [com.rabbitmq.jms.admin.RMQConnectionFactory]
    

    即使在遵循@Ualter Jr. 的回答之后也是因为 .bindings 文件中的条目不正确。

    我更正了 .bindings 文件中的以下 2 行

    ConnectionFactory/ClassName=com.rabbitmq.jms.admin.RMQConnectionFactory --->
    ConnectionFactory/ClassName=javax.jms.ConnectionFactory
    

    YourQueueName/ClassName=com.rabbitmq.jms.admin.RMQDestination --->
    StriimQueue/ClassName=javax.jms.Queue
    

    当我再次遇到这个异常时,我刚刚打开了这个class,发现它需要以下类名

          /*
         * Valid class names are:
         * javax.jms.ConnectionFactory
         * javax.jms.QueueConnectionFactory
         * javax.jms.TopicConnectionFactory
         * javax.jms.Topic
         * javax.jms.Queue
         *
         */
    

    更正这些条目将使现有/新的 JMS 应用程序能够与 RabbitMQ 一起使用。

    【讨论】:

      【解决方案3】:

      我们可以使用下面的 java 代码为 RabbitMQ 生成 .bindings 文件:

      import java.util.Properties;
      import javax.jms.ConnectionFactory;
      import javax.jms.Queue;
      import javax.jms.Topic;
      import javax.naming.Context;
      import javax.naming.InitialContext;
      import javax.naming.Reference;
      import javax.naming.StringRefAddr;
      
      Properties env = new Properties();
          env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");
          env.put(Context.PROVIDER_URL, "file:bindings");
          Context ctx = new InitialContext(env);
      
          Reference connectionFactoryRef = new Reference(ConnectionFactory.class.getName(), RMQObjectFactory.class.getName(), null);
          connectionFactoryRef.add(new StringRefAddr("name", "jms/ConnectionFactory"));
          connectionFactoryRef.add(new StringRefAddr("type", ConnectionFactory.class.getName()));
          connectionFactoryRef.add(new StringRefAddr("factory", RMQObjectFactory.class.getName()));
          connectionFactoryRef.add(new StringRefAddr("host", "$JMS_RABBITMQ_HOST$"));
          connectionFactoryRef.add(new StringRefAddr("port", "$JMS_RABBITMQ_PORT$"));
          ctx.rebind("ConnectionFactory", connectionFactoryRef);
      
          String jndiAppend = "jndi";
          for (int i = 1; i <= 10; i++) {
              String name = String.format("queue%02d", i);
              Reference ref = new Reference(Queue.class.getName(), com.rabbitmq.jms.admin.RMQObjectFactory.class.getName(), null);
              ref.add(new StringRefAddr("name", "jms/Queue"));
              ref.add(new StringRefAddr("type", Queue.class.getName()));
              ref.add(new StringRefAddr("factory", RMQObjectFactory.class.getName()));
              ref.add(new StringRefAddr("destinationName", name));
              ctx.rebind(name+jndiAppend, ref);
      
              name = String.format("topic%02d", i);
              ref = new Reference(Topic.class.getName(), com.rabbitmq.jms.admin.RMQObjectFactory.class.getName(), null);
              ref.add(new StringRefAddr("name", "jms/Topic"));
              ref.add(new StringRefAddr("type", Topic.class.getName()));
              ref.add(new StringRefAddr("factory", RMQObjectFactory.class.getName()));
              ref.add(new StringRefAddr("destinationName", name));
              ctx.rebind(name+jndiAppend, ref);
          }
      

      【讨论】:

        猜你喜欢
        • 2015-04-04
        • 1970-01-01
        • 2020-01-24
        • 2015-11-17
        • 1970-01-01
        • 1970-01-01
        • 2013-02-15
        • 1970-01-01
        • 2011-07-26
        相关资源
        最近更新 更多