如何使用现有JMS应用程序中的RabbitMQ JMS客户端连接RabbitMQ?

时间:2015-10-28 06:31:21

标签: java jms rabbitmq

我有一个通用的独立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类或Provider URL,但它提供了一个JMS Client,它是符合JMS规范的Java客户端的抽象。 RabbitMQ的JMS客户端documentation有一个例子,它将JNDI中的对象定义为资源配置,作为Web应用程序的一部分,但我完全无法弄清楚如何为我的独立应用程序执行类似操作,该应用程序创建基于的命名上下文JNDI提供程序使用JMS客户端的依赖项或从可用的依赖项创建InitialContext。

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

3 个答案:

答案 0 :(得分:8)

为了让 JMS 使用 RabbitMQ ,您必须启用 插件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放入Folder $ RABBITMQ_SERVER \ plugins中。
  2. 使用以下命令启用插件:rabbitmq-plugins enable rabbitmq_jms_topic_exchange
  3. 使用以下命令检查插件是否正常运行:rabbitmq-plugins list
    List of RabbitMQ plugins
  4. 重新启动RabbitMQ - 我不确定它是否真的有必要,但以防万一; - )
  5. 在您的RabbitMQ网站管理(http://localhost:15672/#/exchanges)中,您可以查看您可用的新Exchange: Exchanges of the RabbitMQ
  6. 现在,理论上:-),您已经能够使用标准Java JMS API连接到RabbiMQ服务器。
  7. 请记住,您必须创建.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
    
    

    然后......最后......代码:

    
        Properties environmentParameters = new Properties();
        environmentParameters.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");
        environmentParameters.put(Context.PROVIDER_URL, "file:/C:/rabbitmq-bindings");
        namingContext = new InitialContext(environmentParameters);
    
        ConnectionFactory connFactory = (ConnectionFactory) ctx.lookup("ConnectionFactory");
    
    

答案 1 :(得分:4)

对于遇到此异常的人

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

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

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

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一起使用。

答案 2 :(得分:0)

我们可以使用以下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);
    }