消息驱动Bean(MDB)为应用程序开发提供了事件驱动模型。 MDB的方法不会从客户端代码注入或调用,而是通过从消息传递服务(如Java消息服务(JMS))服务器接收消息来触发。 Java EE规范要求支持JMS,但也可以支持其他消息传递系统。
消息驱动Bean
消息驱动bean(MDB)是一个企业bean。使用MDB,Java EE应用程序异步处理消息。 MDB作为JMS或JCA消息侦听器。
这些消息可以由Java EE组件(例如应用程序客户机,或另一个企业bean)或非Java EE应用程序发送。
集群单例MDB
当MDB被识别为集群单例并部署在集群中时,只有一个节点(服务器)处于活动状态。该节点可以连续消耗消息。 当服务器节点发生故障时,来自集群单例MDB的另一个主动节点开始消耗消息。
将MDB识别为聚类单例
使用以下过程之一将MDB标识为聚类单例:
1、使用聚集单例XML元素。
<jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:c="urn:clustering:1.1" xmlns:d="urn:delivery:1.1" xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-2_0.xsd http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd" version="3.1" impl-version="2.0"> <c:clustering> <ejb-name>HelloWorldQueueMDB</ejb-name> <c:clustered-singleton>true</c:clustered-singleton> </c:clustering> </jboss:ejb-jar>2、在MDB类中,使用@ org.jboss.ejb3.annotation.ClusteredSingleton
此功能不需要额外的配置在服务器。 您需要在群集环境中运行该服务。
传递组
为了支持集群单例MDB,已经创建了一个名为delivery-groups的新功能来管理一组MDB中的传递活动状态。
如果您使用传送依赖关系服务(如@Active或@Passive),请使用传送组。
示例 - jboss-ejb3.xml
<delivery> <ejb-name>MdbName<ejb-name> <delivery-group>passive</delivery-group> </delivery>在服务器端,可以通过将其活动属性设置为true或通过将其活动属性设置为false来禁用传送组来“启用”。
例:
<delivery-groups> <delivery-group name="group" active="true"/> </delivery-groups>可以从管理CLI更新交付组的状态。例如:
./subsystem=ejb3/mdb-delivery-group=group:add
./subsystem=ejb3/mdb-delivery-group=group:remove
./subsystem=ejb3/mdb-delivery-group=group:write-attribute(name=active,value=true)
注意
您必须激活整个集群中的传递组,特别是在集群的所有节点中,因为您不知道集群的哪个节点被选为单例主节点。如果服务器选择节点为单例主节点,并且该节点没有激活所需的传送组,集群中的任何节点都不会收到消息。
此过程显示如何将基于JMS的消息驱动Bean添加到Red Hat JBoss Developer Studio中的项目。此过程创建使用注释的EJB 3.x消息驱动Bean。
先决条件
*您必须在Red Hat JBoss Developer Studio中打开一个现有项目。
*您必须知道bean将要侦听的JMS目标的名称和类型。
*必须在要部署此bean的JBoss EAP配置中启用对Java消息传递服务(JMS)的支持。
在RedHat JBoss Developer Studio中添加一个基于JMS的消息驱动Bean
1、打开创建EJB 3.x消息驱动Bean向导:转到文件→新建→其他。 选择EJB /Message-Driven Bean(EJB 3.x),然后单击下一步按钮。
图4.1 创建EJB 3.x消息驱动Bean向导
2、指定类文件目的地详细信息:有三组详细信息可以在这里指定为bean类:项目,Java类和消息目标。
*项目:
#如果Workspace中存在多个项目,请确保在“项目”菜单中选择了正确的项目。
#将创建新bean的源文件的文件夹是所选项目目录下的ejbModule。 只有在有具体要求的情况下才可以更改。
*Java类:
#必需的字段是:Java包和类名。
#除非您的应用程序的业务逻辑需要它,否则不需要提供超类。
*消息目的地:
这些是您必须为基于JMS的消息驱动Bean提供的详细信息:
*目标名称,它是包含bean将响应的消息的队列或主题名称。
*默认情况下,JMS复选框被选中。 不要改变这个。
*根据需要将目的地类型设置为队列或主题。
单击下一步按钮。
3、输入消息驱动Bean特定信息:这里的默认值适用于使用容器管理事务的基于JMS的消息驱动Bean。
*如果Bean将使用Bean管理的事务,将事务类型更改为Bean。
*如果需要与类名称不同的bean名称,请更改Bean名称。
*已经列出了JMS Message Listener接口。 除非特定于应用程序的业务逻辑,否则不需要添加或删除任何接口。
*留下所选的创建方法存根的复选框。
单击完成按钮。
结果
消息驱动Bean是使用默认构造函数和onMessage()方法的存根方法创建的。 红帽JBoss DeveloperStudio编辑器窗口打开,并显示相应的文件。
在jboss-ejb3.xml部署描述符中,您可以指定要使用的MDB的资源适配器。
要在jboss-ejb3.xml中为MDB指定资源适配器,请使用以下示例。
示例:jboss-ejb3.xml配置MDB资源适配器 <jboss xmlns="http://www.jboss.com/xml/ns/javaee" xmlns:jee="http://java.sun.com/xml/ns/javaee" xmlns:mdb="urn:resource-adapter-binding"> <jee:assembly-descriptor> <mdb:resource-adapter-binding> <jee:ejb-name>MyMDB</jee:ejb-name> <mdb:resource-adapter-name>MyResourceAdapter.rar</mdb:resource-adapter-name> </mdb:resource-adapter-binding> </jee:assembly-descriptor> </jboss>
对于位于EAR中的资源适配器,必须对<mdb:resource-adapter-name>使用以下语法:
*对于另一个EAR中的资源适配器: <mdb:resource-adapter-name>OtherDeployment.ear#MyResourceAdapter.rar</mdb:resource-adapter-name>对于与MDB相同的EAR的资源适配器,可以省略EAR名称:
<mdb:resource-adapter-name>#MyResourceAdapter.rar</mdb:resource-adapter-name>传递活动属性与消息驱动的bean(MDB)相关联,以指示MDB是否正在接收消息。 如果MDB没有收到消息,那么消息将根据主题或队列规则保存在队列或主题中。
您可以使用XML或注释配置“传递活动”属性,您可以使用管理CLI在部署后更改其值。默认情况下,一旦部署MDB,就会激活“传递活动”属性并发送消息。
在jboss-ejb3.xml文件中,将active的值配置为false,以表示MDB在部署后立即不会收到消息: <?xml version="1.1" encoding="UTF-8"?> <jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:d="urn:delivery-active:1.1" xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-2_0.xsd http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd" version="3.1" impl-version="2.0"> <assembly-descriptor> <d:delivery> <ejb-name>HelloWorldQueueMDB</ejb-name> <d:active>false</d:active> </d:delivery> </assembly-descriptor> </jboss:ejb-jar>
如果要将活动值应用于应用程序中的所有MDB,可以使用通配符*代替ejb名称。
您也可以使用org.jboss.ejb3.annotation.DeliveryActive注释。例如: @MessageDriven(name = "HelloWorldMDB", activationConfig = { @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"), @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/HELLOWORLDMDBQueue"), @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge") }) @DeliveryActive(false) public class HelloWorldMDB implements MessageListener { public void onMessage(Message rcvMessage) { // ... } }您可以使用管理CLI更改部署后的“传递活动”属性的值。 这些管理操作动态地更改活动属性的值,启用或禁用MDB的传递。 在运行时,连接到要管理的实例,然后输入要管理传送的MDB的路径。 例如: #连接到您要管理的实例。
cd deployment=jboss-helloworld-mdb.war/subsystem=ejb3/message-driven-bean=HelloWorldMDB #停止交付到MDB :stop-delivery #开始交付到MDB :start-delivery红帽JBoss企业应用程序平台允许您使用@ActivationConfigProperty和@Resource注释在EJB和MDB中启用属性替换。属性替换需要以下配置和代码更改。
*您必须在JBoss EAP服务器配置文件中启用属性替换。
*您必须在服务器配置文件中定义系统属性或在启动JBoss EAP服务器时将其作为参数传递。
*您必须修改应用程序代码才能使用替换变量。
以下示例演示如何修改JBossEAP附带的helloworld-mdb快速入门以使用属性替换。 有关完成的工作示例,请参阅helloworld-mdb-propertysubstitution quickstart。
4.6.1配置服务器以启用属性替换
要在JBoss EAP服务器中启用属性替换,必须将服务器配置文件的ee子系统中的<annotation-property-replacement>属性设置为true。
1.备份服务器配置文件。
helloworld-mdb-property-substitutionquickstart示例需要独立服务器的完整配置文件,因此这是standalone /configuration / standalone-full.xml文件。 如果您在托管域中运行服务器,则这是domain / configuration / domain.xml文件。
2.导航到JBoss EAP安装目录并启动具有完整配置文件的服务器。 $ EAP_HOME/bin/standalone.sh -c standalone-full.xml
注意
对于Windows Server,请使用EAP_HOME\ bin \ standalone.bat脚本。
3.启动管理CLI $ EAP_HOME/bin/jboss-cli.sh --connect
注意
对于Windows Server,请使用EAP_HOME \ bin \ jboss-cli.bat脚本。
4.键入以下命令以启用注释属性替换。 /subsystem=ee:write-attribute(name=annotation-property-replacement,value=true) 你应该看如下的结果: {"outcome" => "success"}
5.查看对JBoss EAP服务器配置文件的更改。 ee子系统现在应该包含以下XML。
示例ee子系统配置: <subsystem xmlns="urn:jboss:domain:ee:4.0"> <annotation-property-replacement>true</annotation-property-replacement> </subsystem>4.6.2定义系统属性
您可以在服务器配置文件中指定系统属性,也可以在启动JBoss EAP服务器时将其作为命令行参数传递。 服务器配置文件中定义的系统属性优先于启动服务器时在命令行上传递的属性。
4.6.2.1定义服务器配置文件中的系统属性
1.如上所述启动管理CLI。
2.使用以下命令语法在JBoss EAP服务器中配置系统属性。
添加系统属性的语法 /system-property=PROPERTY_NAME:add(value=PROPERTY_VALUE)
为helloworld-mdb-propertysubstitution快速启动配置了以下系统属性。
添加系统属性的示例命令 /system-property=property.helloworldmdb.queue:add(value=java:/queue/HELLOWORLDMDBPropQueue) /system-property=property.helloworldmdb.topic:add(value=java:/topic/HELLOWORLDMDBPropTopic) /system-property=property.connection.factory:add(value=java:/ConnectionFactory)
3.查看对JBoss EAP服务器配置文件的更改。以下系统属性现在应显示在<extensions>之后。
示例系统属性配置: <system-properties> <property name="property.helloworldmdb.queue" value="java:/queue/HELLOWORLDMDBPropQueue"/> <property name="property.helloworldmdb.topic" value="java:/topic/HELLOWORLDMDBPropTopic"/> <property name="property.connection.factory" value="java:/ConnectionFactory"/> </system-properties>4.6.2.2在服务器启动时将系统属性作为参数传递
如果您愿意,您可以以-DPROPERTY_NAME= PROPERTY_VALUE的形式启动JBoss EAP服务器,而是在命令行上传递参数。以下是如何传递上一节中定义的系统属性的参数的示例。
示例服务器启动命令传递系统属性 EAP_HOME/bin/standalone.sh -c standalone-full.xml - Dproperty.helloworldmdb.queue=java:/queue/HELLOWORLDMDBPropQueue - Dproperty.helloworldmdb.topic=java:/topic/HELLOWORLDMDBPropTopic - Dproperty.connection.factory=java:/ConnectionFactory 4.6.3 修改应用程序代码以使用系统属性替换 用新定义的系统属性替换硬编码的@ActivationConfigProperty和@Resource注释值。以下是如何更改helloworld-mdb快速启动以使用新定义的系统属性替换的示例。 1.更改HelloWorldQueueMDB类中的@ActivationConfigProperty目标属性值以使用系统属性替换。 @MessageDriven注释现在应该如下所示:
HelloWorldQueueMDB代码示例:
@MessageDriven(name = "HelloWorldQueueMDB", activationConfig = { @ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "${property.helloworldmdb.queue}"), @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"), @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge") }) 2.更改HelloWorldTopicMDB类中的@ActivationConfigProperty目标属性值以使用系统属性替换。 @MessageDriven注释现在应该如下所示: HelloWorldTopicMDB代码示例: @MessageDriven(name = "HelloWorldQTopicMDB", activationConfig = { @ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "${property.helloworldmdb.topic}"), @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"), @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge") }) 3.更改HelloWorldMDBServletClient类中的@Resource注释以使用系统属性替换。代码现在应该是这样的: HelloWorldMDBServletClient代码示例: /** * Definition of the two JMS destinations used by the quickstart * (one queue and one topic). */ @JMSDestinationDefinitions( value = { @JMSDestinationDefinition( name = "java:/${property.helloworldmdb.queue}", interfaceName = "javax.jms.Queue", destinationName = "HelloWorldMDBQueue" ), @JMSDestinationDefinition( name = "java:/${property.helloworldmdb.topic}", interfaceName = "javax.jms.Topic", destinationName = "HelloWorldMDBTopic" ) }) /** * <p> * A simple servlet 3 as client that sends several messages to a queue or a topic. * </p> * * <p> * The servlet is registered and mapped to /HelloWorldMDBServletClient using the {@linkplain WebServlet * @HttpServlet}. * </p> * * @author Serge Pagop (spagop@redhat.com) * */ @WebServlet("/HelloWorldMDBServletClient") public class HelloWorldMDBServletClient extends HttpServlet { private static final long serialVersionUID = -8314035702649252239L; private static final int MSG_COUNT = 5; @Inject private JMSContext context; @Resource(lookup = "${property.helloworldmdb.queue}") private Queue queue; @Resource(lookup = "${property.helloworldmdb.topic}") private Topic topic; <!-- Remainder of code can be found in the `helloworld-mdb-propertysubstitution` quickstart. --> 4.修改activemq-jms.xml文件以使用系统属性替换值。 示例.activemq-jms.xml文件: <?xml version="1.0" encoding="UTF-8"?> <messaging-deployment xmlns="urn:jboss:messaging-activemq-deployment:1.0"> <server> <jms-destinations> <jms-queue name="HELLOWORLDMDBQueue"> <entry name="${property.helloworldmdb.queue}"/> </jms-queue> <jms-topic name="HELLOWORLDMDBTopic"> <entry name="${property.helloworldmdb.topic}"/> </jms-topic> </jms-destinations> </server> </messaging-deployment>5.部署应用程序应用程序现在使用系统属性为@Resource和@ActivationConfigProperty属性值指定的值。
4.7.1 使用注释配置MDB
您可以使用与@ActivationConfigProperty注释对应的@MessageDriven元素和子元素来配置激活属性。@ActivationConfigProperty是一组用于MDB的激活配置属性。 @ActivationConfigProperty注释规范如下: @Target(value={}) @Retention(value=RUNTIME) public @interface ActivationConfigProperty { String propertyName(); String propertyValue(); } 示例@ActivationConfigProperty: @MessageDriven(name="MyMDBName", activationConfig = { @ActivationConfigProperty(propertyName="destinationLookup",propertyValue="queueA"), @ActivationConfigProperty(propertyName = "destinationType",propertyValue = "javax.jms.Queue"), @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"), }) 4.7.2 使用部署描述符配置MDB ejb-jar.xml中的<message-driven>元素将bean定义为MDB。 <activation-config>和元素通过activation-config-property元素包含MDB配置。 示例ejb-jar.xml: <?xml version="1.1" encoding="UTF-8"?> <jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-2_0.xsd http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd" version="3.1"> <enterprise-beans> <message-driven> <ejb-name>MyMDBName</ejb-name> <ejb-class>org.jboss.tutorial.mdb_deployment_descriptor.bean.MyMDBName</ejb-class> <activation-config> <activation-config-property> <activation-config-property-name>destinationLookup</activation-config-property-name> <activation-config-property-value>queueA</activation-config-property-value> </activation-config-property> <activation-config-property> <activation-config-property-name>destinationType</activation-config-property-name> <activation-config-property-value>javax.jms.Queue</activation-config-property-value> </activation-config-property> <activation-config-property> <activation-config-property-name>acknowledgeMode</activation-config-property-name> <activation-config-property-value>Auto-acknowledge</activation-config-property-value> </activation-config-property> </activation-config> </message-driven> <enterprise-beans> </jboss:ejb-jar> 表4.1 激活配置属性由JMS规范定义
Name
Description
destination
与useJNDI = true一起使用此属性与destinationLookup具有相同的含义。使用useJNDI = false,目的地不被查找,但它被实例化。您可以使用此属性而不是destinationLookup。这不是强制性的值。
shareSubscriptions
连接是否配置为共享订阅。
默认值为False。
user
JMS连接的用户。这不是强制性的值。
password
JMS连接的密码。这不是强制性的值。
maxSession
要使用的最大并发会话数。这不是强制性的值。
默认值为15。
transactionTimeout
会话的事务超时(以毫秒为单位)。这不是强制性的值。
如果未指定或为0,该属性将被忽略,并且transactionTimeout不会被覆盖,并且使用事务管理器中定义的默认事务处理时间。
useJNDI
是否使用JNDI查找目的地。
默认值为True。
jndiParams
用于连接的JNDI参数。参数定义为由=
localTx
使用本地事务而不是XA。默认值为False。
setupAttempts
尝试设置JMS连接的次数。在JMS资源可用之前,可能部署MDB。在这种情况下,资源适配器将尝试多次设置,直到资源可用。这仅适用于入站连接。
默认值为-1。
setupInterval
连续尝试设置JMS连接的间隔(以毫秒为单位)。这仅适用于入站连接。
默认值为2000。
rebalanceConnections
是否启用入站连接的重新平衡。
默认值为False。
4.7.3 用例配置MDB的一些示例
*用于MDB接收消息的用例
对于MDB收到消息的基本情况,请参阅随JBoss EAP附带的helloworld-mdb快速入门。
*MDB发送消息的用例
处理消息后,您可能需要通知其他业务系统或回复消息。在这种情况下,您可以从MDB发送消息,如下面的代码片段所示: package org.jboss.as.quickstarts.mdb; import javax.annotation.Resource; import javax.ejb.ActivationConfigProperty; import javax.ejb.MessageDriven; import javax.inject.Inject; import javax.jms.JMSContext; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageListener; import javax.jms.Queue; @MessageDriven(name = "MyMDB", activationConfig = { @ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "queue/MyMDBRequest"), @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"), @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge") }) public class MyMDB implements MessageListener { @Inject private JMSContext jmsContext; @Resource(lookup = "java:/queue/ResponseDefault") private Queue defaultDestination; /** * @see MessageListener#onMessage(Message) */ public void onMessage(Message rcvMessage) { try { Message response = jmsContext.createTextMessage("Response for message " + rcvMessage.getJMSMessageID()); if (rcvMessage.getJMSReplyTo() != null) { jmsContext.createProducer().send(rcvMessage.getJMSReplyTo(), response); } else { jmsContext.createProducer().send(defaultDestination, response); } } catch (JMSException e) { throw new RuntimeException(e); } } }在上面的示例中,MDB收到消息后,它将回复JMSReplyTo中指定的目标或绑定到JNDI名称java:/ queue / ResponseDefault的目标。
*用于配置重新平衡入站连接的MDB的用例 @MessageDriven(name="MyMDBName", activationConfig = { @ActivationConfigProperty(propertyName = "destinationType",propertyValue = "javax.jms.Queue"), @ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "queueA"), @ActivationConfigProperty(propertyName = "rebalanceConnections", propertyValue = "true") } ) 原文地址: https://access.redhat.com/documentation/en-us/red_hat_jboss_enterprise_application_platform/7.0/html/developing_ejb_applications/message_driven_beans-1