.Net中如果需要訊息佇列功能,可以很方便的使用微軟自帶的MSMQ,對應到Java中,這個功能就是JMS(Java Message Service). 下面以Jboss EAP 6.2環境,介紹一下基本的用法:
JMS有二種基本的使用模式,
一種是點對點模式(即“一條”訊息只能從“一個”傳送方傳輸到“一個”接收方) - 這種模式下,傳送方、接收方不必同時線上,訊息在未取回走,一直存放在佇列中。
另一種是釋出/訂閱模式,即一條訊息(該模式下,稱為“主題”),被一個傳送方傳送後,如果有多個接收方訂閱了,這些接收方都能收到訊息 - 這種模式下,釋出者和訂閱都必須同時線上,否則接收不到訊息。
本文主要演示“點對點”模式的基本使用
一、jboss上建立相應的使用者
JMS要求使用者安全認證,即不允許隨便誰都向佇列裡傳送/接收,先在Jboss裡建立一個使用者。
%JBOSS_HOME%/bin/add-user.sh (mac/linux機環境,如果是windows,則是add-user.bat)
執行這個命令後,會出現文字互動介面,參考下圖:
將建立一個msgUser的使用者,提示:jboss eap 6.2安全性比較高,要求使用者的密碼滿足複雜性要求(比如: Password1! ),如果太簡單的密碼,將建立失敗
輸完密碼後,會提示該使用者是否加入某個組,這裡輸入組名:guest (後面建立queue時會用到),參考下圖:
注:上圖中最後一個加密字串,最好記錄一下,某些應用要求安全認證時,需要在配置中配置該串(本文中暫時用不到)
建立完成後,實質上是在%JBOSS_HOME%/standalone/configuration的application-roles.properties、application-users.properties這二個檔案中加了一些內容:
msgUser=5f7e011c53bb155cf99b9eeffccdad4d (這是application-users.properties中增加的內容)
msgUser=guest (這是application-roles.properties中增加的內容)
二、在jboss中建立佇列
把%JBOSS_HOME%/standalone/configuration下的standalone.xml先改個名,然後把standalone-full.xml改成standalone.xml,啟動jboss (即:要以standalone-full.xml中的內容做為配置啟動jboss)
a) 圖形介面方式
進入jboss的管理控制檯,找到Profile -> Subsystems -> Messageing -> Destinations -> 檢視 (參考下圖)
預設情況,應該沒有任何Queue
點選“新增”,Name這裡輸入myQueue(這個可以隨便改),JNDI Names這裡輸入 java:jboss/exported/queue/mytest (最後面的mytest可以隨便改,前面的部分建議不要改)
這樣就建立一個Queue,到目前為止,還沒看到跟安全認證相關的設定,切換到Seurity Settings面板
可以看到,預設情況下,建立的Queue允許"guest"角色 "傳送"訊息(Send這裡是true)、"接收"訊息(Consume這裡是true),這就是為什麼我們在第一步,要把msgUser這個使用者加入guest組的原因
b) standalone.xml 配置方式
其實剛才的操作,最後的結果就是在standalone.xml中生成了如下程式碼:
<subsystemxmlns="urn:jboss:domain:messaging:1.4">
...
<security-settings>
<security-setting match="#">
<permission type="send" roles="guest"/>
<permission type="consume" roles="guest"/>
</security-setting>
</security-settings>
...
<jms-destinations>
<jms-queue name="myQueue">
//注:這一行建議也手動加上,對於單純向Queue傳送訊息而言,加不加效果一樣,
//但是對於Message-drive-bean不加,偶爾會發現無法從queue/mytest接收到訊息
<entry name="queue/mytest"/>
<entryname="java:jboss/exported/queue/mytest"/>
<durable>true</durable>
</jms-queue>
</jms-destinations>
</hornetq-server>
</subsystem>
熟悉這個結構後,可以直接在standalone.xml中修改
c) 單獨在deployments目錄下部署 xxx-jms.xml (注:必須是以-jms.xml結尾的檔案)
內容如下:
<?xmlversion="1.0"encoding="UTF-8"?>
<messaging-deploymentxmlns="urn:jboss:messaging-deployment:1.0"><hornetq-server><jms-destinations><jms-queuename="fred"><entryname="jms/queue/fred"/><entryname="java:jboss/exported/jms/queue/fred"/></jms-queue></jms-destinations></hornetq-server></messaging-deployment>
注:經實際測試,建議所有內容都寫在一行上,不加要其它任何空格或Tab字元,否則部署會失敗(jboss EAP 6.1+版本對xml的校驗極嚴格,哪怕是不可見字元,只要有一個字元校驗失敗,整個部署將失敗)
另外:該方式部署的queue,在管理控制介面上看不到,但是程式碼可訪問
三、編寫測試程式碼
3.1 jndi.properties
要連線到佇列,必然需要一些相關的引數,比如:佇列地址、使用者名稱、密碼、連線“字串”等,如果硬編碼在java程式碼中,顯然不好,我們可以在src目錄下,新建一個jndi.properties檔案,內容參考下圖:
java.naming.factory.initial=org.jboss.naming.remote.client.InitialContextFactory
java.naming.provider.url=remote\://localhost\:4447
java.naming.security.principal=msgUser
java.naming.security.credentials=Password1!
lookup.connectionfactory.name=jms/RemoteConnectionFactory
lookup.destination.name=queue/mytest
前面java開頭是的必須的,後面的二行,是我自己加的(當然大家也可以自行新增任何需要的屬性)
3.2 編寫測試程式碼
(以下程式碼是在jboss-quickstart示例程式碼的基礎上修改而來的)
package org.jboss.as.quickstarts.jms; import java.util.Hashtable; import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException; public class JbossJMSTest { public static void main(String[] args) throws NamingException, JMSException { final String lOOKUP_CONNECTION_FACTORY_NAME = "lookup.connectionfactory.name";
final String lOOKUP_DESTINATION_NAME = "lookup.destination.name"; ConnectionFactory connectionFactory = null;
Connection connection = null;
Session session = null;
MessageProducer producer = null;
MessageConsumer consumer = null;
Destination destination = null;
TextMessage message = null;
Context context = null; try {
// 建立上下文(預設會從應用的classpath下載入jndi.properties做為環境引數)
context = new InitialContext(); // 把環境引數取出來,後面會用到
Hashtable<String, String> env = (Hashtable<String, String>) context
.getEnvironment(); // 查詢連線工廠
connectionFactory = (ConnectionFactory) context.lookup(env
.get(lOOKUP_CONNECTION_FACTORY_NAME)); // 查詢目標佇列
destination = (Destination) context.lookup(env
.get(lOOKUP_DESTINATION_NAME)); // 建立連線
connection = connectionFactory.createConnection(
env.get(Context.SECURITY_PRINCIPAL),
env.get(Context.SECURITY_CREDENTIALS)); // 建立會話
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // 建立生產者(即傳送者)
producer = session.createProducer(destination); // 建立消費者(即接收者)
consumer = session.createConsumer(destination); // 開始連線
connection.start(); // 傳送訊息
message = session.createTextMessage("菩提樹下的楊過,歡迎使用JMS!");
producer.send(message); // 接收訊息
message = (TextMessage) consumer.receive(5000); // 列印訊息
System.out.println(message.getText()); } catch (NamingException e) {
e.printStackTrace();
} catch (JMSException e) {
e.printStackTrace();
} finally {
// 釋放資源
if (context != null) {
context.close();
} if (connection != null) {
connection.close();
} }
} }
JbossJMSTest
執行結果:
最後附加上pom.xml內容:
<?xml version="1.0"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>cnblogs</groupId>
<artifactId>helloworld-jms</artifactId>
<version>1.0</version>
<packaging>jar</packaging> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> <dependencies>
<dependency>
<groupId>org.jboss.as</groupId>
<artifactId>jboss-as-jms-client-bom</artifactId>
<version>7.2.0.Final-redhat-8</version>
<type>pom</type>
</dependency>
</dependencies> </project>
pom.xml
示例原始碼下載:helloworld-jms.zip