使用GlassFish实现JMS消息传递

对于当今的电子商务来说,在分布式异构系统之间进行通信已经成为不可避免的需求。现在,随着 Java 消息服务 (JMS) 等消息标准的出现,开发松散耦合的同步或异步通信分布式系统(用于交换商务数 据和事件)已经非常简单。

本文主要介绍如何使用 JMS 和消息驱动 Beans( Message-Driven Beans ,MDB )进行消息传递,特 别是企业消息传递的详细信息。本文还将介绍 GlassFish 应用程序服务器的消息传递功能及其配置设置 。为了更好地说明这些技术,在此还将讨论一个简单的实时应用案例及其实施细节。

消息传递

简单地说,消息传递是在双方间发生的通信。企业消息传递可以定义为两个软件组件或两个应用程序 之间的通信。消息传递就像发送物理信件一样简单,信件发送者准备好消息、给出正确的邮寄地址,然后 选择正确的邮寄服务。在企业消息传递中也要有一个以特定格式向目的地发送消息的消息发送者。目的地 是面向消息的中间件或者是帮助交换消息的消息队列。而且还要有从目的地同步或异步接收消息的消息用 户。并不强制规定发送者和接受者在同样的时间在线,也不强制规定他们必须相互认识才能交换信息。

消息传递系统的关键好处是保持分布式系统松懈地耦合。 松懈耦合使消息传递解决方案不同于其他的 紧密耦合通信解决方案(例如,远程方法调用 (Remote Method Invocation,RMI)、公共对象请求代理 体系结构(Common Object Request Broker Architecture,CORBA)等等)。

JMS 消息传递

Java 消息服务( Java Messaging Service )是一个建立在 Java 2 平台企业版本 ( Java 2 Platform, Enterprise Edition,Java EE )之上的消息传递 API。它定义了一组创建、发送和接收消息 常用接口。

JMS 支持两种消息传递模式:

点到点( PTP )模式

发布-订阅模式

点到点消息传递模式依赖于消息队列概念,也就是,将其中的消息地址写到称作队列 的特定目的地。 接受者从队列中使用消息,对其进行处理,然后确认收到消息。点到点消息传递模式的主要特征有:

每条消息有一个使用者。

在发送者和接收者之间没有时间依赖性。

在发布-订阅模式中,消息地址被写到一个称作主题 的目的地。消息生成器发布消息,使用者订阅消 息。这种消息传递模式的主要特征有:

每条消息有多个使用者。

在发送者和接受者之间存在时间依赖性,也就是,使用者必须积极接受消息。即使订阅者暂停使用, JMS API 也允许订阅者创建持久订阅方式 来接收消息。使用持久订阅方式,JMS 提供器一直保留订阅的 消息直到收到取消订阅的请求或订阅过期。

消息类型

JMS 支持 5 种消息类型:

文本: 一条简单的文本消息或一个 java.lang.String 对象。

对象: Serializable(可序列化) Java 对象。

字节: 简单的字节流。

映射表: 一组名称 —— 值对集合。

数据流: 原始值数据流。

消息驱动 Beans(Message-Driven Beans,MDB)

消息驱动 bean 的工作是帮助异步处理消息。MDB 担任 JMS 消息的侦听器。JMS 客户机不能找到 MDB 并直接调用方法;相反,客户机将消息发送到 MDB 正在侦听的目的地。当接收到消息时,EJB 容器调用 MDB 的onMessage 方法。这种方法通常将消息转换为 5 种 JMS 消息类型中的 1 种,并作为应用程序的 业务逻辑进行处理。MDB 以异步模式运行,并且是无状态、事务感知的。这些功能使 MDB 更具较高的伸 缩性,为企业发送消息提供了健壮的解决方案。

GlassFish 中的 JMS 支持

GlassFish 是开发和部署 Java EE 应用程序和 web 服务的开源应用程序服务器。该服务器与 Java Enterprise Edition 5 ( Java EE 5 ) 兼容,实际上是 Java EE 5 的参考实现。

GlassFish 通过提供一个完全集成的 JMS 提供器为 JMS 消息传递提供巨大支持。Java Message Service API 通过将 Sun Java System Message Queue 软件集成到 GlassFish,并提供透明的 JMS 消息 传递支持得以实现。

GlassFish 支持两种 JMS 资源: 连接工厂和目的地资源。

连接工厂是一种由 JMS 客户机使用用于创建 JMS 提供器连接的对象。连接工厂有 3 种类型:

连接工厂: 由点到点以及发布 —— 订阅消息传递模式使用。

队列连接工厂: 由点到点消息传递模式使用。

主题连接工厂: 由发布 —— 订阅消息传递模式使用。

目的地是一个对象,JMS 消息生成器使用这个对象以便将消息邮寄到该对象;它也是一种资源,JMS 消息使用者使用来自该资源的消息。支持目的地的类型有:

队列: 队列是点到点通信的目的地。

主题: 主题是发布 —— 订阅通信的目的地。

下列内容是 GlassFish 支持的一些 JMS 连接功能。

连接池

GlassFish 服务器自动汇集 JMS 连接。用户可以使用 GlassFish 管理控制台或 asadmin 命令设置连 接池属性。在创建连接工厂时配置连接池细节。由 GlassFish 支持的一些连接池参数有:

连接池的初始值和最小值: 在连接池中指示初始连接的数量。这也是给连接池设置的最小连接数量。

连接池最大值: 在连接池中指示可用连接的最大数量。

连接池重新调整的数量: 当连接池达到空闲超时时,应该移除的连接数量。

空闲超时: 在连接池中连接可以保持空闲的最长时间。

最大等待时间: 在发送连接超时以前系统等待的最长时间。

运行失败行为: 在发生运行失败的情况下,连接可能被中断然后重新连接。

事务支持: 事务支持的级别。支持事务的类型有“本地事务”、“XA 事务”和“没有事务”。

连接验证: 如果选择了该属性,将连接传递到应用程序之前要对其进行验证。

连接故障转移

如果连接丢失,该功能启用应用程序服务器重新连接到消息代理。如果启用重新连接并且无法连接初 始消息代理,那么应用程序服务器将尝试重新连接另一个可用代理。用户可以配置重试数量和重试之间的 时间间隔。

访问应用程序中的 JMS 资源

在 GlassFish 中, 可以以两种方式访问连接工厂和目的地: 使用 Java 命名和目录接口(Java Naming and DirecTory InterfaceTM,JNDI)查找或使用注释。

JNDI 查找

JMS 客户机使用 JNDI API 查找连接工厂和消息目的地。

InitialContext jndi = new InitialContext();// Lookup queue connection facToryQueueConnectionFacTory qFacTory = (QueueConnectionFacTory)jndi.         lookup("webTrackerConnFacTory");// Lookup queueQueue queue = (Queue)jndi.lookup("webTrackerQueue");

注释

在 Java SE 5.0 中介绍过注释,它是编程的声明性样式。注释与元标记一样,可以应用于类、构造函 数、方法、变量等等。

注释 @Resource 用于查找连接工厂和目的地。在 Web 应用程序中,如果注释放在变量上,那么 servlet 容器将注入请求的资源;也就是,注释变量将在为请求提供服务之前使用适当的值进行预先填充 。

@Resource(name="connFacTory", mappedName="webTrackerConnFacTory")private QueueConnectionFacTory qFacTory;@Resource(name="jmsQueue", mappedName="webTrackerQueue")private Queue queue;

使消息传递正常运行

迄今为止,我们已经讨论了如何将 JMS 和 MDB 一起运行来实施异步消息传递。我们也了解了 GlassFish 的功能和它提供的 JMS 支持。现在,我们将了解如何在称作 “Web Access Tracker”的实时 应用案例的帮助下发挥这些技术的作用。

Web Access Tracker 帮助站点管理员或商务使用者监测用户请求统计,例如一天的访问数量、经常访 问的页面、页面/服务请求时间、要求服务的时间等等。在下一部分我将解释一个解决方案,在不破坏实 际应用程序性能的情况下收集被用户访问的每个网页的访问信息。您可以在参考资料部分的链接中下载该 样例的完整资源代码,以及它的可部署二进制文件。

解决方案

在其他技术(例如 Java XML 绑定架构 、 Java Server Faces (JSF)、 servlet 筛选器等等)的帮 助下,选择基于 JMS 的消息传递解决方案捕获和处理 web 访问数据。GlassFish 为 JMS 消息传递以及 部署应用程序提供了支持。

演示应用程序使用 servlet 筛选器截取用户请求并从请求消息标题中提取所需信息。然后,该信息将 作为 JMS 消息邮寄给消息队列。消息通过消息驱动 bean 这一 JMS 消息使用者异步传递。从消息中收集 的数据将被永久保留到 XML 数据存储区中。JAXB 是用于访问和将数据存储到 XML 文件的首选技术。使 用 JSF 开发用户界面。

系统需求

Java EE 5

GlassFish 应用程序服务器

其他库文件: Apache 服务器的 commons-beanutils.jar、 commons-collections.jar 和 commons- logging.jar 文件

Servlet 筛选器

servlet 筛选器或者筛选向资源发出的请求,或者筛选从资源中发出的响应,或者对两者同时执行筛 选任务。您可以通过实施 Filter 界面书写自己的筛选器。该界面中的主要方法是执行核心筛选行为的 doFilter 方法。您还可以在筛选类中实施 初始化和 销毁 方法。这些方法由 servlet 容器调用用于初 始化和销毁筛选器。

样例应用程序使用称作 WebTrackerFilter 的 servlet 筛选器捕获属于请求的信息;也就是,被请求 页面的 URL 、主机 IP、请求时间等等。从请求收集的信息将作为数据传输对象( Data Transfer Object,DTO )发送给消息分发器做进一步处理。

public void doFilter(ServletRequest request,     ServletResponse response, FilterChain chain)     throws java.io.IOException, ServletException {   HttpServletRequest httpServletRequest = (HttpServletRequest)               request;   HttpServletResponse httpServletResponse = (HttpServletResponse)               response;   // Extract required header parameters and set it in DTO   RequestData data = new RequestData();   data.setQueryString(request.getQueryString());   data.setRemoteAddress(request.getRemoteAddr());   data.setRequestURI(request.getRequestURI());   data.setResponseTime(elapsedTime);   data.setUserAgent(request.getHeader("User-Agent"));   // send the data to message dispatcher   messagedispatcher.sendRequestData(data);   chain.doFilter(httpServletRequest, httpServletResponse);}

配置 Servlet 筛选器

我们已经了解如何编写自定义筛选器程序,那么现在我们需要在 web 应用程序部署的描述符中配置 筛选器类;也就是 web.xml 文件。筛选器类可以在部署描述符文件中通过添加  元素 进行配置。该元素创建筛选器的名称以及筛选器实现类的名称。使用 元素可以 将 servlet/URL 模式映射到筛选器中。这将导致 WebTrackerFilter 被 URL 模式为 *.html 的所有请求 调用。下列元素显示如何配置 WebTrackerFilter。

   WebTrackerFilter   demo.webtracker.filter.WebTrackerFilter    WebTrackerFilter    *.html

异步消息传递

使用 WebTrackerFilter 可获得请求信息;下一步是开发 JMS 客户机以 JMS 消息的形式将数据邮寄 到消息队列。选择点到点模式进行消息传递。

为典型 JMS 客户机开发的代码片断如下所示。您需要使用从 JNDI 树中检索到的 JMS 管理对象 InitialContext,执行连接工厂和目的地的 JNDI 查找操作。另一种选择是,在运行时使用注释来注入 JMS 资源。在代码中使用的 webTrackerConnFacTory 和 webTrackerQueue 分别是连接工厂和目的地的 JNDI 名称。客户机假设这些资源已经在 GlassFish 中进行了配置,那么配置需要在执行这些代码之前完 成。参考 “在 GlassFish 中配置 JMS 资源” 部分来了解如何在 GlassFish 中配置 JMS 资源。

在连接工厂上使用 createQueueConnection 方法,可以创建一个到 JMS 服务提供器的 Connection( 连接)。连接提供对基础消息传输的访问。

接下来的任务是使用 createSession 方法在 Connection 对象上创建 JMS Session(会话)。会话是 生成和使用消息的单线程上下文。createSession 的第一个参数决定是否执行 JMS 会话,第二个参数指 示消息确认模式。在本样例中,不执行会话,而是在接受消息时自动确认会话。

您还有必要创建一个用于将消息发送到目的地的 MessageProducer。最后一步是创建 JMS ObjectMessage 并设置请求数据为消息。然后将消息发送到消息队列。

// Get queue connection facToryQueueConnectionFacTory qFacTory = (QueueConnectionFacTory)jndi.         lookup("webTrackerConnFacTory");// Get queueQueue queue = (Queue)jndi.lookup("webTrackerQueue");// Get queue connectionQueueConnection qConn = (QueueConnection)qFacTory.         createConnection();// Get sessionSession session = qConn.createSession(false,       Session.AUTO_ACKNOWLEDGE);// Set the JMS messageObjectMessage msg = session.createObjectMessage();msg.setObject(data);// Send JMS messagesession.createProducer(jmsLoc.getMessageQueue()).send(msg);

消息驱动 Beans

消息驱动 bean 将作为 JMS 消息的侦听器。当消息到达队列时,容器调用 MDB 的 onMessage() 方法 。该方法将消息转换为数据原始消息类型(也就是,ObjectMessage ),然后进行格式化并永久保存到数据 存储区。MDB 实现 MessageDrivenBean 界面和消息类型支持的 MessageListener 界面(可选);也就是 ,如果 bean 支持 JMS,javax.jms.MessageListener将是要实现的界面。

下面给出了接收 JMS 消息的代码:

public void onMessage(Message message) {       if (message instanceof ObjectMessage) {    RequestData data = (RequestData)((ObjectMessage)message).              getObject();    // persist data   }}

如果您正在使用 Java EE 5,MDB 可以使用 @MessageDriven 注释进行注释。该注释包含一个 mappedName 元素,该元素指定 bean 将要侦听的消息队列的 JNDI 名称 。MDB 可以使用 @Resource 注 释注入 MessageDrivenContext 资源。在这种情况下,您不必声明 EJB 部署描述符的 bean 细节。MDB 的最前面几行如下所示:

@MessageDriven(mappedName = "webTrackerQueue")public class WebTrackerEJB implements MessageListener {/** Context for the MDB. */@Resourceprivate MessageDrivenContext mdbContext;.........

Java XML 绑定架构(JAXB)

从用户请求中捕获的数据可以永久存储到数据存储区。出于简单,在本样例中 XML 数据存储区已经选 定。JAXB 是解编和编组 XML 文档的首选技术。JAXB 提供了一种方便途径,通过将 XML 模式绑定到 Java 表示并使用 Java 对象访问和处理 XML 内容。XML 的 Java 对象表示可以按照下列步骤创建:

准备数据存储区的 XML 结构。

创建 XML 模式定义(XML Schema Definition,XSD)。参考在 webtracker-src/config 目录中提供 的 webAccess-sample.xml 和 webAccess.xsd 文件,寻找在本样例中使用的关于 XML 数据存储区和模式 定义的更多细节。

使用 JAXB 的 XJC 命令来生成提供 XSD 所需的 Java 文件。在 /bin 目录 中包含 XJC.bat 文件。

XML 文档解编

数据解编是从 XML 文档中创建对象树的过程。要解编 XML 文档,您需要创建 JAXBContext。 JAXBContext 提供管理 XML/Java 绑定信息的抽象。含有模式派生类的 Java 包应作为一个参数传递,以 便创建 JAXBContext。使用 JAXBContext 创建的 XML 解组器可用于检索 XML 文档的根元素。

解编 XML 数据文件的代码如下所示:

// create a JAXBContextJAXBContext jc = JAXBContext.newInstance       ("demo.webtracker.xmlgen");// create UnMarshallerUnmarshaller unmarshaller = jc.createUnmarshaller();JAXBElement rootElement = (JAXBElement)unmarshaller.unmarshal       (new FileInputStream(xmlDataSTorePath));// Get the root elementWebAccess Access = (WebAccess)rootElement.getValue();

XML 文档编组

编组过程是从内容树中创建 XML 文档。要编组 XML 文档,您需要创建 JAXBContext。

编组 XML 数据文件的代码如下所示:

// create a JAXBContextJAXBContext jc = JAXBContext.newInstance       ("demo.webtracker.xmlgen");// create a Marshaller and marshal to webAccessLog.xmlMarshaller marshaller = jc.createMarshaller();// Converts java object to XML datamarshaller.marshal(AccessData, new File(xmlDataSTorePath));

在 GlassFish 中配 置 JMS 资源

如果 JMS 客户机要向目的地发送消息,连接工厂和目的地的资源需要在 GlassFish 中进行配置。这 些资源可以通过 GlassFish 的管理控制台创建,也可以通过 asadmin 命令创建。

创建 JMS 连接工厂

JMS 连接工厂允许应用程序以编程方式创建其他 JMS 对象。使用管理控制台按照下列步骤配置连接工 厂:

登录 GlassFish 管理控制台。

从左侧的导航条展开 Resources -> JMSResources 菜单。

选择 Connection FacTories 节点。

单击 New 按钮创建一个新的连接工厂。

输入下列内容:

将 “webTrackerConnFacTory” 作为 JNDI Name(JNDI 名称)。这是连接工厂的惟一 JNDI 名称。 JMS 客户机使用该名称查找连接工厂。JNDI 名称可以多达 255 个字符,而且必须只包含字母数字、下划 线、破折号、或点号字符。

将“javax.jms.QueueConnectionFacTory”作为 Resource Type(资源类型)。在样例应用程序中, 我们已经选择了点到点消息传递模式,因此资源类型应该是 QueueConnectionFacTory。

将 “Webtracker Connection FacTory”作为 Description (描述)名称。

单击 OK 按钮。

创建 JMS 消息队列

JMS 目的地作为消息的存储库。使用管理控制台按照下列步骤配置连接工厂:

登录 GlassFish 管理控制台。

从左侧的导航条展开 Resources -> JMSResources 菜单。

选择 Destination Resources。

单击 New 按钮以便创建目的地。

输入下列内容:

将 “webTrackerQueue” 作为 JNDI Name(JNDI 名称)。这是目的地的惟一 JNDI 名称。JMS 客户 机使用该名称查找消息队列。

将 “webTrackerQueue” 作为物理目的地。这是在消息代理中的目的地名称。

将“javax.jms.Queue”作为 Resource Type。由于我们采用点到点模式,资源类型应该是 Queue(队 列)。

将 “Webtracker Queue Destination”作为 Description(描述)名称。

单击 OK 按钮。

在 GlassFish 中部署应用程序

将应用程序打包,作为由 web 模块和 EJB 模块组成的企业应用归档(enterprise application archive,EAR )文件。web 模块处理应用程序的用户界面。将消息驱动 bean 和其他数据访问类打包作 为 EJB 模块。下列步骤解释了在 GlassFish 中样例应用程序的部署。

登录 GlassFish 管理控制台。

从左侧的导航条选择 Applications -> Enterprise Applications。

单击 Deploy 按钮以便部署 webtracker 应用程序。

浏览 webTracker.ear 文件并上传它。

单击 OK 按钮。

将 webtracker-src/config 中提供的 webAccess.xml 文件复制到任意本地目录下。添加称作 xmlsTore.path 的系统属性,并将它指向该目录。您可以从 GlassFish 管理控制台中选择 Application Server -> JVM Settings -> JVM Options -> Add JVM Option 设置系统属性。样例条目为 – DxmlsTore.path=C:/temp/webAccessLog.xml。

部署描述符ejb-jar.xml

用于样例应用程序的 ejb-jar.xml 部署描述符如下所示: 您必须将 WebTrackerEJB 声明为消息驱动 bean 并将 javax.jms.Queue 作为消息目的地的类型。如果您已经在 Java EE 5 中注释了 MDB,那么可 以忽略该配置。

  Web Tracker App          WebTrackerEJB     WebTrackerEJB     demo.webtracker.ejb.WebTrackerEJB    Container          javax.jms.Queue           Tor>              WebTrackerEJB      *           Required     

sun-ejb-jar.xml

用于样例应用程序的 sun-ejb-jar.xml 部署描述符如下所示: 连接工厂和队列的 JNDI 名称将在描 述符中声明。如果您已经在 Java EE 5 中注释了 MDB,那么可以忽略该配置。

         WebTrackerEJB    webTrackerQueue          webTrackerConnFacTory        

测试应用程序

现在已经成功部署了应用程序,准备进行测试。可以使用下列 URL 访问应用程序的主页:

http://:/webTracker

图 1 显示了主页的快照。

图 1. Web Access Tracker 的主页

web 访问报告可以通过单击在左侧导航条提供的 Web Access Info 链接查看。在图 2 中显示该报告 。

图 2. Web 访问报告

结束语

在本文中我们探索了 JMS 消息传递和 GlassFish 的消息传递功能。毫无疑问,JMS 已经赢得了广泛 的行业支持并成为功能强大的企业消息传递解决方案。在本文中解释的应用案例,真正地演示了 JMS 使 用消息传递解决方案解决实时问题的美妙之处。

我等你用尽了所有的哀伤;而你眼中却有我所不懂的凄凉。

使用GlassFish实现JMS消息传递

相关文章:

你感兴趣的文章:

标签云: