Java消息服務

Java消息服務（Java Message Service，JMS）應用程式接口是一個Java平台中關於面向消息中間件（MOM）的API，用於在兩個應用程式之間，或分布式系統中發送消息，進行異步通信。Java消息服務是一個與具體平台無關的API，絕大多數MOM提供商都對JMS提供支持。

Java消息服務的規範包括兩種消息模式，點對點和發布者／訂閱者。許多提供商支持這一通用框架因此，程式設計師可以在他們的分布式軟體中實現面向消息的操作，這些操作將具有不同面向消息中間件產品的可移植性。

Java消息服務支持同步和異步的消息處理，在某些場景下，同步消息是必要的；在其他場景下，異步消息比同步消息操作更加便利。

Java消息服務支持面向事件的方法接收消息，事件驅動的程序設計現在被廣泛認為是一種富有成效的程序設計範例，程式設計師們都相當熟悉。

在應用系統開發時，Java消息服務可以推遲選擇面對消息中間件產品，也可以在不同的面對消息中間件切換。

## 歷史

Java消息服務是一個在 Java標準化組織（JCP）內開發的標準（代號JSR 914）。2001年6月25日，Java消息服務發布JMS 1.0.2b，2002年3月18日Java消息服務發布 1.1，統一了消息域。

## 體系架構

### JMS元素

JMS由以下元素組成。

JMS提供者：連接面向消息中間件的，JMS接口的一個實現。提供者可以是Java平台的JMS實現，也可以是非Java平台的面向消息中間件的適配器。

JMS客戶：生產或消費消息的基於Java的應用程式或對象。

JMS生產者：創建並發送消息的JMS客戶。

JMS消費者：接收消息的JMS客戶。

JMS消息：包括可以在JMS客戶之間傳遞的數據的對象

JMS隊列：一個容納那些被發送的等待閱讀的消息的區域。隊列暗示，這些消息將按照順序發送。一旦一個消息被閱讀，該消息將被從隊列中移走。

JMS主題：一種支持發送消息給多個訂閱者的機制。

### JMS模型

Java消息服務應用程式結構支持兩種模型：

- 點對點或隊列模型
- 發布/訂閱模型

在點對點或隊列模型下，一個生產者向一個特定的隊列發布消息，一個消費者從該隊列中讀取消息。這裡，生產者知道消費者的隊列，並直接將消息發送到消費者的隊列。這種模式被概括為：

- 只有一個消費者將獲得消息
- 生產者不需要在接收者消費該消息期間處於運行狀態，接收者也同樣不需要在消息發送時處於運行狀態。
- 每一個成功處理的消息都由接收者簽收

發布者／訂閱者模型支持向一個特定的消息主題發布消息。0或多個訂閱者可能對接收來自特定消息主題的消息感興趣。在這種模型下，發布者和訂閱者彼此不知道對方。這種模式好比是匿名公告板。這種模式被概括為：

- 多個消費者可以獲得消息
- 在發布者和訂閱者之間存在時間依賴性。發布者需要建立一個訂閱（subscription），以便客戶能夠訂閱。訂閱者必須保持持續的活動狀態以接收消息，除非訂閱者建立了持久的訂閱。在那種情況下，在訂閱者未連接時發布的消息將在訂閱者重新連接時重新發布。

使用Java語言，JMS提供了將應用與提供數據的傳輸層相分離的方式。同一組Java類可以通過JNDI中關於提供者的資訊，連接不同的JMS提供者。這一組類首先使用一個連接工廠以連接到隊列或主題，然後發送或發布消息。在接收端，客戶接收或訂閱這些消息。

## JMS應用程式接口

Java消息服務的API在javax/jms包中提供。

### javax/jms 接口（連接工廠）

使用者用來創建到JMS提供者的連接的被管對象。JMS客戶通過可移植的接口訪問連接，這樣當下層的實現改變時，代碼不需要進行修改。管理員在JNDI名字空間中配置連接工廠，這樣，JMS客戶才能夠查找到它們。根據消息類型的不同，使用者將使用隊列連接工廠，或者主題連接工廠。

### javax/jms 接口（連接）

連接代表了應用程式和消息伺服器之間的通信鏈路。在獲得了連接工廠後，就可以創建一個與JMS提供者的連接。根據不同的連接類型，連接允許用戶創建會話，以發送和接收隊列和主題到目標。

### javax/jms 接口（目標）

目標是一個包裝了消息目標標識符的被管對象，消息目標是指消息發布和接收的地點，或者是隊列，或者是主題。JMS管理員創建這些對象，然後使用者通過JNDI發現它們。和連接工廠一樣，管理員可以創建兩種類型的目標，點對點模型的隊列，以及發布者／訂閱者模型的主題。

### javax/jms 接口（消息消費者）

由會話創建的對象，用於接收發送到目標的消息。消費者可以同步地（阻塞模式），或異步（非阻塞）接收隊列和主題類型的消息。

### javax/jms 接口（消息生產者）

由會話創建的對象，用於發送消息到目標。使用者可以創建某個目標的發送者，也可以創建一個通用的發送者，在發送消息時指定目標。

### javax/jms 接口（消息）

是在消費者和生產者之間傳送的對象，也就是說從一個應用程式創送到另一個應用程式。一個消息有三個主要部分：

- 消息頭（必須）：包含用於識別和為消息尋找路由的操作設置。
- 一組消息屬性（可選）：包含額外的屬性，支持其他提供者和使用者的兼容。可以創建定製的欄位和過濾器（消息選擇器）。
- 一個消息體（可選）：允許用戶創建五種類型的消息（文本消息，映射消息，字節消息，流消息和對象消息）。

消息接口非常靈活，並提供了許多方式來定製消息的內容。

### javax/jms 接口（會話）

表示一個單線程的上下文，用於發送和接收消息。由於會話是單線程的，所以消息是連續的，就是說消息是按照發送的順序一個一個接收的。會話的好處是它支持事務。如果使用者選擇了事務支持，會話上下文將保存一組消息，直到事務被提交才發送這些消息。在提交事務之前，使用者可以使用回滾操作取消這些消息。一個會話允許用戶創建消息生產者來發送消息，創建消息消費者來接收消息。

## JMS提供者實現

要使用Java消息服務，你必須要有一個JMS提供者，管理會話和隊列。現在既有開源的提供者也有專有的提供者。

開源的提供者包括：

- Kafka
- Apache ActiveMQ
- JBoss 社區所研發的 HornetQ
- Joram
- Coridan的 MantaRay
- The OpenJMS Group 的OpenJMS

專有的提供者包括：

- BEA的BEA WebLogic Server JMS
- TIBCO軟體公司的 EMS
- GigaSpaces Technologies 的GigaSpaces
- Softwired 2006的iBus
- IONA Technologies的IONA JMS
- SeeBeyond 的IQManager（2005年8月被Sun Microsystems併購）
- webMethods的JMS+ - http://www.webmethods.com
- my-channels 的Nirvana
- Sonic Software的SonicMQ
- IBM的WebSphere MQ

一個詳盡的JMS提供者對比矩陣可以在 這裡 看到。

如果你計劃在一個伺服器集群中運行你的程序，你需要檢查提供者是否實現了對負載均衡和故障恢復的支持。

## 外部連結

- Sun's JMS Overview
- JSR 914 (JMS 1.0 and 1.1)
- GigaSpaces Technologies JavaSpaces approach to JMS