文章出處

.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.propertiesapplication-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示例代碼的基礎上修改而來的)

 1 package org.jboss.as.quickstarts.jms;
 2 
 3 import java.util.Hashtable;
 4 
 5 import javax.jms.Connection;
 6 import javax.jms.ConnectionFactory;
 7 import javax.jms.Destination;
 8 import javax.jms.JMSException;
 9 import javax.jms.MessageConsumer;
10 import javax.jms.MessageProducer;
11 import javax.jms.Session;
12 import javax.jms.TextMessage;
13 import javax.naming.Context;
14 import javax.naming.InitialContext;
15 import javax.naming.NamingException;
16 
17 
18 
19 public class JbossJMSTest {
20 
21     public static void main(String[] args) throws NamingException, JMSException {
22 
23         final String lOOKUP_CONNECTION_FACTORY_NAME = "lookup.connectionfactory.name";
24         final String lOOKUP_DESTINATION_NAME = "lookup.destination.name";
25 
26         ConnectionFactory connectionFactory = null;
27         Connection connection = null;
28         Session session = null;
29         MessageProducer producer = null;
30         MessageConsumer consumer = null;
31         Destination destination = null;
32         TextMessage message = null;
33         Context context = null;
34 
35         try {
36             // 創建上下文(默認會從應用的classpath下加載jndi.properties做為環境參數)
37             context = new InitialContext();
38 
39             // 把環境參數取出來,后面會用到
40             Hashtable<String, String> env = (Hashtable<String, String>) context
41                     .getEnvironment();
42 
43             // 查找連接工廠
44             connectionFactory = (ConnectionFactory) context.lookup(env
45                     .get(lOOKUP_CONNECTION_FACTORY_NAME));
46 
47             // 查找目標隊列
48             destination = (Destination) context.lookup(env
49                     .get(lOOKUP_DESTINATION_NAME));
50 
51             // 創建連接
52             connection = connectionFactory.createConnection(
53                     env.get(Context.SECURITY_PRINCIPAL),
54                     env.get(Context.SECURITY_CREDENTIALS));
55 
56             // 創建會話
57             session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
58 
59             // 創建生產者(即發送者)
60             producer = session.createProducer(destination);
61 
62             // 創建消費者(即接收者)
63             consumer = session.createConsumer(destination);
64 
65             // 開始連接
66             connection.start();
67 
68             // 發送消息
69             message = session.createTextMessage("菩提樹下的楊過,歡迎使用JMS!");
70             producer.send(message);
71 
72             // 接收消息
73             message = (TextMessage) consumer.receive(5000);
74 
75             // 打印消息
76             System.out.println(message.getText());
77 
78         } catch (NamingException e) {
79             e.printStackTrace();
80         } catch (JMSException e) {
81             e.printStackTrace();
82         } finally {
83             // 釋放資源
84             if (context != null) {
85                 context.close();
86             }
87 
88             if (connection != null) {
89                 connection.close();
90             }
91 
92         }
93     }
94 
95 }
JbossJMSTest

 

運行結果:

最后附加上pom.xml內容:

 1 <?xml version="1.0"?>
 2 
 3 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 5     <modelVersion>4.0.0</modelVersion>
 6 
 7     <groupId>cnblogs</groupId>
 8     <artifactId>helloworld-jms</artifactId>
 9     <version>1.0</version>
10     <packaging>jar</packaging>
11 
12     <properties>
13         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
14     </properties>
15 
16     <dependencies>
17         <dependency>
18             <groupId>org.jboss.as</groupId>
19             <artifactId>jboss-as-jms-client-bom</artifactId>
20             <version>7.2.0.Final-redhat-8</version>
21             <type>pom</type>
22         </dependency>
23     </dependencies>
24 
25 </project>
pom.xml

示例源代碼下載:helloworld-jms.zip


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()