Spring之JMS之接受消息

23.4.1 同步接受

JMS一般是异步处理,也有可能同步消费消息。重载receive(..)方法提供了这个功能。在同步接受期间,调用线程会一直阻塞直到消息可用。这会是很危险的操作,因为调用线程可能随机发生阻塞。receiveTimeout属性指定了接收器在放弃等待一条消息前应该等待的时间。


23.4.2 异步接受---消息驱动 POJOs


需注意Spring通过使用@JmsListener也提供注解监听端并提供一个开放底层程序化注册端点。这是迄今为止设置异步接收器最方便的方式。


与EJB中MDB相似,JMS 消息使用消息驱动的POJO即MDP作为接收器。MDP的一个约束是必须要实现javax.jms.MessageListener接口。请注意这种情况,你的POJO在多线程下接受消息时,确保线程安全很重要。


下面是一个简单的MDP的实现:

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

public class ExampleListener implements MessageListener {

    public void onMessage(Message message) {
        if (message instanceof TextMessage) {
            try {
                System.out.println(((TextMessage) message).getText());
            }
            catch (JMSException ex) {
                throw new RuntimeException(ex);
            }
        }
        else {
            throw new IllegalArgumentException("Message must be of type TextMessage");
        }
    }

}

只要实现了 MessageListener接口,就该创建一个消息监听容器了。


找出下面的例子中如何在Spring中定义和配置一个消息监听容器的(这里是DefaultMessageListenerContainer


<!-- this is the Message Driven POJO (MDP) -->
<bean id="messageListener" class="jmsexample.ExampleListener" />

<!-- and this is the message listener container -->
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
    <property name="connectionFactory" ref="connectionFactory"/>
    <property name="destination" ref="destination"/>
    <property name="messageListener" ref="messageListener" />
</bean>

23.4.3 SessionAwareMessageListener接口


SessionAwareMessageListener是Spring指定的接口,用于提供与JMS MessageListener接口相同的功能,但是也提供给消息处理方法,借此从消息接受的对象中访问JMS会话。

package org.springframework.jms.listener;

public interface SessionAwareMessageListener {

    void onMessage(Message message, Session session) throws JMSException;

}

你可以选择性地使你的MDPs实现这个接口(参考标准的JMS MessageListener接口),如果你想你的MDPs能够响应任何接受的消息(使用 onMessage(Message, Session)方法中的Session)。所有的Spring的消息监听容器支持MDPs实现 MessageListener或者 SessionAwareMessageListener接口。实现了 SessionAwareMessageListener接口的类有点瑕疵,因为其与Spring耦合。是否选择使用这个接口完全取决于应用程序开发者或架构师。


请注意SessionAwareMessageListener接口的'onMessage(..)'方法抛出了JMSException。与标准的JMSMessageListener接口比较,当使用SessionAwareMessageListener接口时,客户端代码负责处理任何异常抛出。


23.4.4 MessageListenerAdapter


MessageListenerAdapter类是Spring异步消息支持中的最终组件:概括性说,其允许你暴露几乎任何类作为MDP(当然了也有一些约束)。


考虑下面的接口定义。注意到这个接口既不继承MessageListener,也不继承SessionAwareMessageListener接口,借助MessageListenerAdapter类,也可以用作MDP。也要注意到不同的消息处理方法根据不同的Message类型的内容(其可以接受和处理的额)如何强制性类型转换。


public interface MessageDelegate {

    void handleMessage(String message);

    void handleMessage(Map message);

    void handleMessage(byte[] message);

    void handleMessage(Serializable message);

}
public class DefaultMessageDelegate implements MessageDelegate {
    // implementation elided for clarity...
}

尤其是,上述的 MessageDelegate接口的实现类(这里是 DefaultMessageDelegate类)没有任何的JMS依赖。完全是一个POJO,通过以下配置转换为一个MDP。


<!-- this is the Message Driven POJO (MDP) -->
<bean id="messageListener" class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
    <constructor-arg>
        <bean class="jmsexample.DefaultMessageDelegate"/>
    </constructor-arg>
</bean>

<!-- and this is the message listener container... -->
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
    <property name="connectionFactory" ref="connectionFactory"/>
    <property name="destination" ref="destination"/>
    <property name="messageListener" ref="messageListener" />
</bean>

下面是另一个MDP的例子,其能处理JMS TextMessage消息的接受。注意消息处理方法如何调用'receive'( MessageListenerAdapter类中消息处理方法名默认为 'handleMessage') ,但是它是可配置的(如下所示)。也注意到 'receive(..)'方法如何强制类型转化为仅接受和响应JMS TextMessage消息。


public interface TextMessageDelegate {

    void receive(TextMessage message);

}
public class DefaultTextMessageDelegate implements TextMessageDelegate {
    // implementation elided for clarity...
}

相应的 MessageListenerAdapter配置如下:

<bean id="messageListener" class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
    <constructor-arg>
        <bean class="jmsexample.DefaultTextMessageDelegate"/>
    </constructor-arg>
    <property name="defaultListenerMethod" value="receive"/>
    <!-- we don't want automatic message context extraction -->
    <property name="messageConverter">
        <null/>
    </property>
</bean>


请注意上述的'messageListener'接受了一个JMS 消息,而不是TextMessage类型,将抛出一个IllegalStateException异常。MessageListenerAdapter类的另一个功能是自动发送回一个响应消息,如果处理器方法返回一个有效值的话。看下面的接口和类:


public interface ResponsiveTextMessageDelegate {

    // notice the return type...
    String receive(TextMessage message);

}
public class DefaultResponsiveTextMessageDelegate implements ResponsiveTextMessageDelegate {
    // implementation elided for clarity...
}

如果上述的 DefaultResponsiveTextMessageDelegateMessageListenerAdapter联合使用,从执行的 'receive(..)方法中返回一个非空值,将转换为一个 TextMessage。结果 TextMessage将在稍后发送到Destination(如果存在),其在JMS 的初始 Message的Reply-To属性中定义,或者 MessageListenerAdapter定义的默认的 Destination(如果已经配置了);如果没有发现 Destination,则抛出异常 InvalidDestinationException(请注意这个异常将不被容忍,并将传送到调用回调)。


23..4.5 事物内处理消息


在一个事物中调用消息监听器仅仅需要重新配置监听容器。

定位资源事物可以通过监听容器定义的sessionTransacted标示激活。每个消息监听调用将在一个活性的JMS事物中执行,并在监听执行失败时,消息接受会回滚。发送一个响应消息(借助SessionAwareMessageListener)将是相同本地事物一部分,但是另外的资源操作(比如数据库访问)将分开操作。这通常需要在监听实现中进行多重的消息查找,囊括了这种情况,提交了数据库处理但是消息处理提交失败。


<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
    <property name="connectionFactory" ref="connectionFactory"/>
    <property name="destination" ref="destination"/>
    <property name="messageListener" ref="messageListener"/>
    <property name="sessionTransacted" value="true"/>
</bean>

对于外部管理事物中的多人参与情况,你需要配置一个事物管理器并使用一个监听容器,其支持外部事物管理:一般的是 DefaultMessageListenerContainer


对于XA事物参与配置的消息监听容器,你将想要配置一个JtaTransactionManager(默认地,委托给Java EE服务器的事物子系统)。注意到底层的JMS ConnectionFactory需要是XA-capable并注册你的JTA 事物协调器。


<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>

之后 你只需要将其添加到你早期的容器配置中。容器就负责剩余的工作了:

<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
    <property name="connectionFactory" ref="connectionFactory"/>
    <property name="destination" ref="destination"/>
    <property name="messageListener" ref="messageListener"/>
    <property name="transactionManager" ref="transactionManager"/>
</bean>




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
什么是消息 消息是一个用于在组件和应用程序之间通讯的的方法。消息之间的传递是点对点的。任何终端之间都可以相互接受和发送消息。并且每个终端都必须遵守如下的规则 -> 创建消息 -> 发送消息 -> 接收消息 -> 读取消息 为什么要使用消息 理由很简单,消息是一个分布式的低耦合通讯方案。A发送一个消息到一个agent ,B作为接受者去agent上获取消息。但是A,B不需要同时到agent上去注册。agent作为一个中转为A,B提供搞效率的通讯服务。 Java消息服务支持两种消息模型:Point-to-Point消息(P2P)和发布订阅消息(Publish Subscribe messaging,简称Pub/Sub)。JMS规范并不要求供应商同时支持这两种消息模型,但开发者应该熟悉这两种消息模型的优势与缺点。 企业消息产品(或者有时称为面向消息的中间件产品)正逐渐成为公司内操作集成的关 键组件。这些产品可以将分离的业务组件组合成一个可靠灵活的系统。 除了传统的 MOM 供应商,企业消息产品也可以由数据库供应商和许多与网络相关的公 司来提供。 Java 语言的客户端和 Java 语言的中间层服务必须能够使用这些消息系统。JMS 为 Java 语言程序提供了一个通用的方式来获取这些系统。 JMS 是一个接口和相关语义的集合,那些语义定义了 JMS 客户端如何获取企业消息产品 的功能。 由于消息是点对点的,所以 JMS 的所有用户都称为客户端(clients)。JMS 应用由定义 消息的应用和一系列与他们交互的客户端组成。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值