JNDI 支援

連線能力 > 容器 > JNDI 支援

ActiveMQ Classic 可與任何能夠儲存 Java 物件的 JNDI 提供者搭配使用。然而,通常需要一個 JNDI 初始環境才能運行許多 JMS 範例程式,例如Sun 的 JMS 教學

因此,我們提供了一個簡單的 JNDI InitialContextFactory,可用於查找 JMS 連接工廠物件以及目標物件。例如,如果您將此jndi.properties檔案放在您的 classpath 上,您可以在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://localhost

# 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 新增至您的 classpath。如果程式庫不在 classpath 中,您將在執行時收到 ClassNotFoundException。如果收到 ClassNotFoundException,請嘗試列印出 classpath 並檢查它是否存在。您也可以使用 -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 檔案,並以延遲方式建立主題和佇列。主題和佇列的前置詞會被剝除,因此 JNDI 名稱從前置詞之後開始。

一旦您編輯並準備好 jndi.properties,它需要可讓您的應用程式存取。最簡單的方法是將 jndi.properties 新增到 jar 檔案中。當呼叫 new InitialContext() 時,它將掃描資源並找到該檔案。如果收到 javax.naming.NamingException,通常表示 jndi.properties 檔案無法存取。

您也可以嘗試使用屬性檔案的實例或 map 來建立新的初始環境。例如,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://localhost:61616)

VM 傳輸參考中提供了更多選項

範例 Java 程式碼

一旦您在 classpath 上配置了 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 專案標誌是 The Apache Software Foundation 的商標。版權 © 2024,The Apache Software Foundation。根據Apache License 2.0授權。