JNDI 支持

连接性 > 容器 > JNDI 支持

ActiveMQ Classic 可以与任何能够存储 Java 对象的 JNDI 提供程序一起使用。但是,要运行许多 JMS 示例程序(如 Sun 的 JMS 教程),通常需要 JNDI 初始上下文。

因此,我们提供了一个简单的 JNDI InitialContextFactory,它可用于查找 JMS 连接工厂对象以及目标对象。例如,如果您将此 jndi.properties 文件放在您的类路径上,您可以在 InitialContext 中查找 ConnectionFactory 对象和 Destinations 等。

java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory

# use the following property to configure the default connector
java.naming.provider.url = vm://127.0.0.1

# use the following property to specify the JNDI name the connection factory
# should appear as. 
#connectionFactoryNames = connectionFactory, queueConnectionFactory, topicConnectionFactry

# register some queues in JNDI using the form
# queue.[jndiName] = [physicalName]
queue.MyQueue = example.MyQueue


# register some topics in JNDI using the form
# topic.[jndiName] = [physicalName]
topic.MyTopic = example.MyTopic

您可以编辑 jndi.properties 文件来配置 ActiveMQConnectionFactory 的属性,例如 brokerURL 以及是否应该有嵌入式代理等。有关更多详细信息,请参阅 如何在连接中嵌入代理

ActiveMQ Classic JNDI 教程

这是一个关于如何设置和使用 JNDI 创建与 ActiveMQ Classic 连接的快速单页教程。首先,ActiveMQ Classic 不会提供完整的 JNDI 服务器。这意味着 JMS 客户端需要使用属性文件来创建 JNDI IntialContextFactory。如果您需要示例属性文件,您可以查看源代码分发版 https://github.com/apache/activemq/blob/master/activemq-unit-tests/src/test/resources/jndi.properties。在我们继续之前,这里列出了一些属性。

名称
java.naming.factory.initial org.apache.activemq.jndi.ActiveMQInitialContextFactory
java.naming.provider.url tcp://hostname:61616
topic.MyTopic example.MyTopic

确保将 activemq-_<version>_.jarspring-1.x.jar 添加到您的类路径中。如果库不在类路径中,您将在运行时遇到 ClassNotFoundException。如果您遇到 ClassNotFoundException,请尝试打印出类路径并检查它是否存在。您也可以使用 -verbose 选项运行 ActiveMQ Classic 以验证 jar 是否已正确加载。

示例代码

// Create a new intial context, which loads from jndi.properties file: 
javax.naming.Context ctx = new javax.naming.InitialContext(); 
// Lookup the connection factory: 
javax.jms.TopicConnectionFactory factory = (javax.jms.TopicConnectionFactory)ctx.lookup("ConnectionFactory"); 
// Create a new TopicConnection for pub/sub messaging: 
javax.jms.TopicConnection conn = factory.getTopicConnection(); 
// Lookup an existing topic: 
javax.jms.Topic mytopic = (javax.jms.Topic)ctx.lookup("MyTopic"); 
// Create a new TopicSession for the client: 
javax.jms.TopicSession session = conn.createTopicSession(false,TopicSession.AUTO_ACKNOWLEDGE); 
// Create a new subscriber to receive messages: 
javax.jms.TopicSubscriber subscriber = session.createSubscriber(mytopic);

请注意,示例中的主题名称是 MyTopic。ActiveMQ Classic 将读取 jndi.properties 文件,并以延迟方式创建主题和队列。将删除前缀 topic 和 queue,因此 JNDI 名称从前缀之后开始。

准备好 jndi.properties 文件后,您的应用程序需要能够访问它。最简单的方法是将 jndi.properties 添加到 jar 文件中。当调用 new InitialContext() 时,它将扫描资源并找到该文件。如果您遇到 javax.naming.NamingException,通常意味着 jndi.properties 文件不可访问。

您也可以尝试使用属性文件实例或映射创建新的初始上下文。例如,JMS 规范推荐的方法可以正常工作。

规范推荐的示例

javaProperties props = new Properties(); 
props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.jndi.ActiveMQInitialContextFactory"); 
props.setProperty(Context.PROVIDER_URL, "tcp://hostname:61616"); 
javax.naming.Context ctx = new InitialContext(props);

如果 ActiveMQ Classic 嵌入到 EJB 容器中,您需要查看容器文档以获取正确的 JNDI 值。

动态创建目标

为了简化使用 JNDI 的程序的配置,有两种动态上下文,即

  • dynamicQueues
  • dynamicTopics

这些允许您在没有任何配置的情况下使用 JNDI 查找队列和主题。

例如,如果您使用以下名称在 JNDI 中查找

dynamicQueues/FOO.BAR

您将获得一个名为 FOO.BARActiveMQQueue。如果您能够轻松地重新配置 JNDI 名称以用于在 JNDI 中查找某些内容,但这并不希望必须重新配置 jndi.properties 以匹配,那么这将非常方便。

使用嵌入式代理

在与 JMS 客户端相同的 JVM 中使用嵌入式代理通常很有用。为此,请参阅 如何在连接中嵌入代理

如果您想将嵌入式代理与您的 JNDI 提供程序一起使用,您只需使用 VM 传输 连接到您 URL 中的代理即可。例如,要创建一个纯 JVM 中的代理,请使用此 URI

vm://locahost

如果您想自定义代理,请使用类似以下内容

vm:broker:(tcp://127.0.0.1:61616)

VM 传输参考 中提供了更多选项。

示例 Java 代码

在类路径上配置 JNDI 后,您可以运行任何正常的 JMS 应用程序,例如以下 示例。请注意,Java 代码仅使用纯 JMS API,与 ActiveMQ Classic 无关。

/**
 * The SimpleQueueSender class consists only of a main method,
 * which sends several messages to a queue. 
 * 
 * Run this program in conjunction with SimpleQueueReceiver. 
 * Specify a queue name on the command line when you run the 
 * program. By default, the program sends one message. Specify 
 * a number after the queue name to send that number of messages. 
 */ 
 
package org.apache.activemq.demo; 

import javax.jms.Connection; 
import javax.jms.ConnectionFactory; 
import javax.jms.Destination; 
import javax.jms.JMSException; 
import javax.jms.MessageProducer; 
import javax.jms.Session; 
import javax.jms.TextMessage; 
import javax.naming.Context; 
import javax.naming.InitialContext; 
import javax.naming.NamingException; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
/**
 * A simple polymorphic JMS producer which can work with Queues or Topics which 
 * uses JNDI to lookup the JMS connection factory and destination.
 */ 
public final class SimpleProducer { 
   private static final Logger LOG = LoggerFactory.getLogger(SimpleProducer.class); 
   private SimpleProducer() {}  
  
   /**
    * @param args the destination name to send to and optionally, the number of 
    * messages to send 
    */ 
   public static void main(String[] args) { 
      Context jndiContext; 
      ConnectionFactory connectionFactory; 
      Connection connection; 
      Session session; 
      Destination destination; 
      MessageProducer producer; 
      String destinationName; 
      final int numMsgs;  
      
      if ((args.length < 1) || (args.length > 2)) { 
         LOG.info("Usage: java SimpleProducer <destination-name> [<number-of-messages>]"); System.exit(1); 
      }  
      
      destinationName = args[0]; 
      LOG.info("Destination name is " + destinationName); 
      
      if (args.length == 2) { 
         numMsgs = (new Integer(args[1])).intValue(); 
      } else { 
         numMsgs = 1; 
      } 
      
      /*
       * Create a JNDI API InitialContext object 
       */
      try { 
         jndiContext = new InitialContext(); 
      } catch (NamingException e) { 
         LOG.info("Could not create JNDI API context: " + e.toString()); 
         System.exit(1); 
      }
      
      /* 
       * Look up connection factory and destination. 
       */
      try { 
         connectionFactory = (ConnectionFactory)jndiContext.lookup("ConnectionFactory"); 
         destination = (Destination)jndiContext.lookup(destinationName); 
      } catch (NamingException e) { 
         LOG.info("JNDI API lookup failed: " + e); 
         System.exit(1); 
      }  
      
      /*
       * Create connection. Create session from connection; false means 
       * session is not transacted. Create sender and text message. Send 
       * messages, varying text slightly. Send end-of-messages message. 
       * Finally, close the connection. 
       */ 
      try { 
         connection = connectionFactory.createConnection(); 
         session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 
         producer = session.createProducer(destination); 
         TextMessage message = session.createTextMessage();  
         for (int i = 0; i < numMsgs; i++) { 
            message.setText("This is message " + (i + 1)); 
            LOG.info("Sending message: " + message.getText()); producer.send(message); 
         }  
         
         /*
          * Send a non-text control message indicating end of messages. 
          */ 
         producer.send(session.createMessage()); 
      } catch (JMSException e) { 
         LOG.info("Exception occurred: " + e); 
      } finally { 
         if (connection != null) { 
            try { 
               connection.close(); 
            } catch (JMSException ignored) {
            } 
         } 
      } 
   } 
}

Apache、ActiveMQ、Apache ActiveMQ、Apache 羽毛标志和 Apache ActiveMQ 项目标志是 Apache 软件基金会的商标。版权所有 © 2024,Apache 软件基金会。根据 Apache 许可证 2.0 许可。