Spring Framework 开发参考手册 之十四 JMS支持

第 14 章 JMS支持

14.1. 介绍

Spring提供一个用于简化JMS API使用的抽象层框架,并且对用户屏蔽JMS API中从1.0.2到1.1版本之间的不同。

JMS大体上被分为两个功能块,消息生产和消息消费。在J2EE环境,由消息驱动的bean提供了异步消费消息的能力 。而在独立的应用中,则必须创建MessageListener或ConnectionConsumer来消费消息。 JmsTemplate的主要功能就是产生消息。Spring的未来版本将会提供,在一个独立的环境中处理异步消息。

org.springframework.jms.core包提供使用JMS的核心功能。 就象为JDBC提供的JdbcTemplate一样, 它提供了JMS模板类来处理资源的创建和释放以简化JMS的使用。 这个Spring的模板类的公共设计原则就是通过提供helper方法去执行公共的操作, 以及将实际的处理任务委派到用户实现的回调接口上,从而以完成更复杂的操作。 JMS模板遵循这样的设计原则。这些类提供众多便利的方法来发送消息、异步地接收消息、 将JMS会话和消息产生者暴露给用户。

org.springframework.jms.support包提供JMSException的转换功能。 它将checked JMSException级别转换到一个对应的unchecked异常级别, 任何checked的javax.jms.JMSException异常的子类都被包装到unchecked的UncategorizedJmsException。 org.springframework.jms.support.converter 包提供一个MessageConverter的抽象进行Java对象和JMS消息之间的转换。 org.springframework.jms.support.destination提供多种管理JMS目的地的策略, 例如为存储在JNDI中的目的地提供一个服务定位器。

最后,org.springframework.jms.connection包提供一个适合在独立应用中使用的 ConnectionFactory的实现。它还为JMS提供了一个Spring的PlatformTransactionManager的实现。 这让JMS作为一个事务资源和Spring的事务管理机制可以集成在一起使用。

14.2. 域的统一

JMS主要发布了两个规范版本,1.0.2和1.1。JMS1.0.2定义了两种消息域, 点对点(队列)和发布/订阅(主题)。 JMS1.0.2的API为每个消息领域提供了类似的类体系来处理这两种不同的消息域。 结果,客户端应用在使用JMS API时要了解是在使用哪种消息域。 JMS 1.1引进了统一域的概念来最小化这两种域之间功能和客户端API的差别。 举个例子,如果你使用的是一个JMS 1.1的消息供应者, 你可以使用同一个Session事务性地在一个域接收一个消息后并且从另一个域中产生一个消息。

JMS 1.1的规范发布于2002年4月,并且在2003年11月成为J2EE 1.4的一个组成部分, 结果,现在大多数使用的应用服务器只支持JMS 1.0.2的规范.

14.3. JmsTemplate

这里为JmsTemplate提供了两个实现。 JmsTemplate类使用JMS 1.1的API, 而子类 JmsTemplate102使用了JMS 1.0.2的API。

使用JmsTemplate的代码只需要实现规范中定义的回调接口。 在JmsTemplate中通过调用代码让MessageCreator回调接口用所提供的会话(Session)创建消息。 然而,为了顾及更复杂的JMS API应用,回调接口SessionCallback将JMS会话提供给用户, 并且暴露Session和MessageProducer。

JMS API暴露两种发送方法,一种接受交付模式、优先级和存活时间作为服务质量(QOS)参数, 而另一种使用缺省值作为QOS参数(无需参数)方式。由于在JmsTemplate中有多种发送方法, QOS参数用bean属性进行暴露设置,从而避免在一系列发送方法中重复。同样地, 使用setReceiveTimeout属性值来设置用于异步接收调用的超时值。

某些JMS供应者允许通过ConnectionFactory的配置来设置缺省的QOS值。 这样在调用MessageProducer的发送方法send(Destination destination, Message message) 时效率更高,因为调用时直接会使用QOS缺省值,而不再用JMS规范中定义的值。 所以,为了提供对QOS值域的统一管理,JmsTemplate必须通过设置布尔值属性isExplicitQosEnabled 为true,使它能够使用自己的QOS值。

14.3.1. ConnectionFactory

JmsTemplate请求一个对ConnectionFactory的引用。 ConnectionFactory是JMS规范的一部分,并被作为使用JMS的入口。 客户端应用通常作为一个工厂配合JMS提供者去创建连接,并封装一系列的配置参数, 其中一些是和供应商相关的,例如SSL的配置选项。

当在EJB内使用JMS时,供应商提供JMS接口的实现,以至于可以参与声明式事务的管理, 提供连接池和会话池。为了使用这个实现,J2EE容器一般要求你在EJB或servlet部署描述符中将JMS连接工厂声明为 resource-ref。为确保可以在EJB内使用JmsTemplate的这些特性, 客户应用应当确保它能引用其中的ConnectionFactory实现。

Spring提供ConnectionFactory接口的一个实现,SingleConnectionFactory, 它将在所有的createConnection调用中返回一个相同的连接, 并忽略close的调用。这在测试和独立的环境中相当有用, 因为同一个连接可以被用于多个JmsTemplate调用以跨越多个事务。 SingleConnectionFactory接受一个通常来自JNDI的标准ConnectionFactory的引用。

14.3.2. 事务管理

Spring为单个JMS ConnectionFactory提供一个JmsTransactionManager来管理事务。 它允许JMS应用可以利用第7章中描述的Spring的事务管理特性。JmsTransactionManager 从指定的ConnectionFactory将一个Connection/Session对绑定到线程。然而,在一个J2EE环境, ConnectionFactory将缓存连接和会话,所以被绑定到线程的实例依赖于缓存的行为。 在一个独立的环境,使用Spring的SingleConnectionFactory将导致使用单独的JMS连接, 而且每个连接都有自己的会话。JmsTemplate也能和JtaTransactionManager 以及XA-capable的JMS ConnectionFactory一起使用以完成分布式事务。

当使用JMS API从连接创建一个Session时,跨越管理性和非管理性事务的复用代码可能会让人困惑。这是因为JMS API只提供一个工厂方法来创建会话,并且它要求事务和确认模式的值。在受管理的环境下,由事务结构环境负责设置这些值,这样在供应商包装的JMS连接中可以忽略这些值。当在一个非管理性的环境中使用JmsTemplate时,你可以通过使用属性SessionTransactedSessionAcknowledgeMode来指定这些值。当在JmsTemplate中使用PlatformTransactionManager时,模板将一直被赋予一个事务性JMS会话。

14.3.3. Destination管理

Destination,象ConnectionFactories一样,是可以在JNDI中进行存储和提取的JMS管理对象。当配置一个Spring应用上下文,可以使用JNDI工厂类JndiObjectFactoryBean在你的对象引用上执行依赖注入到JMS Destination。然而,如果在应用中有大量的Destination,或者JMS供应商提供了特有的高级Destination管理特性,这个策略常常显得很笨重。高级Destination管理的例子如创建动态destination或支持destination的命名层次。JmsTemplate将destination名字到JMS destination对象的解析委派到一个DestinationResolver接口的实现。DynamicDestinationResolverJmsTemplate 使用的默认实现,并且提供动态destination解析。同时JndiDestinationResolver作为JNDI包含的destination的服务定位器,并且可选择地退回来使用DynamicDestinationResolver提供的行为。

相当常见的是在一个JMS应用中所使用的destination只有在运行时才知道,因此,当一个应用被部署时,它不能被创建。这经常是因为交互系统组件之间的共享应用逻辑是在运行时按照已知的命名规范创建destination。虽然动态destination的创建不是JMS规范的一部分,但是许多供应商已经提供了这个功能。用户为所建的动态destination定义名字,这样区别于来临时destination,并且动态destination不会被注册到JNDI中。创建动态destination所使用的API在不同的供应商之间差别很大,因为destination所关联的属性是供应商特有的。然而,有时由供应商作出的一个简单的实现选择是忽略JMS规范中的警告,并使用TopicSession的方法createTopic(String topicName)或者QueueSession的方法createQueue(String queueName)来创建一个拥有默认属性的新destination。依赖于供应商的实现,DynamicDestinationResolver可能也能创建一个物理上的destination,而不是只是解析。

布尔属性PubSubDomain被用来配置JmsTemplate使用什么样的JMS域。这个属性的默认值是false,使用点到点的域,也就是队列。在1.0.2的实现中,这个属性值用来决定JmsTemplate将消息发送到一个队列还是主题。这个标志在1.1的实现中对发送操作没有影响。然而,在这两个实现中,这个属性决定了通过DestinationResolver的实现来解析动态destination的行为。

你还可以通过属性DefaultDestination配置一个带有默认destination的JmsTemplate。默认的destination被使用时,它的发送和接收操作不需要指定一个特定的destination。

14.4. 使用JmsTemplate

要开始使用JmsTemplate前,你需要选择JMS 1.0.2的实现,JmsTemplate102,还是JMS 1.1的实现,JmsTemplate。检查一下你的JMS供应者支持那个版本。

14.4.1. 发送消息

JmsTemplate包含许多有用的方法来发送消息。这些发送方法可以使用javax.jms.Destination对象指定destination,也可以使用字符串在JNDI中查找destination。没有destination参数的发送方法使用默认的destination。这里有个例子使用1.0.2的实现发送消息到一个队列。

import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Queue;
import javax.jms.Session;

import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.JmsTemplate102;
import org.springframework.jms.core.MessageCreator;

public class JmsQueueSender {

  private JmsTemplate jt;

  private ConnectionFactory connFactory;

  private Queue queue;

  public void simpleSend() {
    jt = new JmsTemplate102(connFactory, false);
    jt.send(queue, new MessageCreator() {
      public Message createMessage(Session session) throws JMSException {
        return session.createTextMessage("hello queue world");
      }
    });
  }

  public void setConnectionFactory(ConnectionFactory cf) {
      connFactory = cf;
  }

  public void setQueue(Queue q) {
      queue = q;
  }

}
      

这个例子使用MessageCreator回调接口从所提供的会话对象中创建一个文本消息,并且通过一个ConnectionFactory的引用和指定消息域的布尔值来创建JmsTemplate。BeanFactory使用一个没有参数的构造方法和setConnectionFactory/Queue方法来用构造实例。simpleSend方法在下面修改为发送消息到一个主题而不是队列。

public void simpleSend() {
  jt = new JmsTemplate102(connFactory, true);
  jt.send(topic, new MessageCreator() {
     public Message createMessage(Session session) throws JMSException {
        return session.createTextMessage("hello topic world");
     }
  });
}     
      

当在应用上下文中配置JMS 1.0.2时,重要的是记得设定布尔属性 PubSubDomain的值以确定你是要发送到队列还是主题。

方法send(String destinationName, MessageCreator c)让你利用destination的名字发送消息。如果这个名字在JNDI中注册,你应当将模板中的DesinationResolver属性设置为JndiDestinationResolver的一个实例。

如果你创建JmsTemplate并指定一个默认的destination,send(MessageCreator c)发送消息到这个destination。

14.4.2. 同步接收

虽然JMS一般都是应用在异步操作,但它也可能同步接收消息。重载的receive方法就提供这个功能。在同步接收时,调用线程被阻塞直到收到一个消息。这是一个危险的操作,因为调用线程可能会被无限期的阻塞。receiveTimeout属性指定接收者在放弃等待一个消息前要等多久。

14.4.3. 使用消息转换器

为了更容易的发送域模式对象,JmsTemplate有多种将一个Java对象作为消息数据内容的发送方法。在JmsTemplate中重载方法convertAndSendreceiveAndConvert,可以将转换过程委派到MessageConverter接口的一个实例。这个接口定义了一个简单的Java对象和JMS消息之间进行转换的约定。它的默认实现SimpleMessageConverter支持在StringTextMessagebyte[]BytesMesssagejava.util.MapMapMessage之间进行转换。通过使用转换器,你的应用代码可以专注于通过JMS发送或接收的业务对象,并不用为了怎样将它描述为一个JMS消息而费心。

沙箱目前包含MapMessageConverter,它使用反射在JavaBean和MapMessage之间进行转换。你还可以选择使用XML组包的转换器,如JAXB、Castor、XMLBeans或Xstream,来创建一个TextMessage来描述该对象。

消息属性、消息头和消息体的设置,一般不能被封装在一个转换器类中,为了调整它们,接口MessagePostProcessor可以使你在消息转换后,发送前,访问消息。下面的例子展示了如何在一个java.util.Map被转换为消息之后修改一个消息的头和属性。

public void sendWithConversion() {
    Map m = new HashMap();
    m.put("Name", "Mark");
    m.put("Age", new Integer(35));
    jt.convertAndSend("testQueue", m, new MessagePostProcessor() {

         public Message postProcessMessage(Message message)
            throws JMSException {
            message.setIntProperty("AccountID", 1234);
            message.setJMSCorrelationID("123-00001");

            return message;
        }
    });
}
      

这是一个由上面得到的消息

MapMessage={ 
  Header={ 
    ... standard headers ...
    CorrelationID={123-00001} 
  } 
  Properties={ 
    AccountID={Integer:1234}
  } 
  Fields={ 
    Name={String:Mark} 
    Age={Integer:35} 
  } 
}
      

14.4.4. SessionCallback和ProducerCallback

虽然发送操作涵盖了很多普通的使用场景,但是有些情况你需要在JMS Session或MessageProducer上执行多个操作。SessionCallbackProduerCallback分别暴露了JMS Session和Session/MessageProducer对。JmsTemplate的execute()方法会执行这些接口上的回调方法。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spring Framework 是一个开源的Java平台,它为开发企业级Java应用程序提供了一种全面的编程和配置模型。Spring Framework 的核心特性包括依赖注入(DI),面向切面编程(AOP),以及支持各种数据访问技术的集成。以下是一些Spring Framework开发技术: 1. Spring Boot:Spring Boot是一个快速构建Spring应用程序的框架。它基于Spring Framework,并提供了自动配置、快速开发、无代码生成等特性。 2. Spring MVC:Spring MVC是一种基于MVC(Model-View-Controller)设计模式的Web框架。它提供了一个灵活的模型-视图-控制器架构,可以支持各种Web应用程序的开发。 3. Spring Data:Spring Data是一个用于访问各种数据存储技术的框架。它提供了一组通用的数据访问接口和实现,可以简化数据访问的开发工作。 4. Spring Security:Spring Security是一个用于身份验证和授权的框架。它提供了各种安全特性,包括基于角色的访问控制、加密、会话管理和单点登录等。 5. Spring Integration:Spring Integration是一个用于构建集成应用程序的框架。它提供了一组通用的消息传递模型和实现,可以简化异构系统之间的集成工作。 6. Spring Cloud:Spring Cloud是一个用于构建分布式系统的框架。它提供了一组通用的服务注册、配置中心、负载均衡等特性,可以帮助开发人员构建高可用性、可伸缩性的分布式系统。 ### 回答2: Spring Framework是一个开源的Java企业应用开发框架,它提供了一套全面的技术解决方案,用于开发可扩展和高效的企业级应用程序。 首先,Spring Framework具有依赖注入(Dependency Injection)功能,通过IoC容器管理对象之间的依赖关系。这种方式降低了对象之间的耦合度,使得应用程序更易于测试、维护和扩展。 其次,Spring Framework提供了面向切面编程(Aspect-Oriented Programming)的支持。通过使用切面(Aspect)将一些通用的横切关注点(如事务管理、日志记录等)从业务逻辑中分离出来,从而提高代码的可重用性和可维护性。 此外,Spring Framework还提供了一套丰富的整合和扩展模块,如Spring MVC用于开发Web应用,Spring Data用于与各种数据库进行交互,Spring Security用于实现应用程序的安全等。 值得一提的是,Spring Framework具有很高的灵活性和可扩展性。它支持各种各样的应用场景和技术栈,并且可以与其他框架和技术无缝集成。 总的来说,Spring Framework是一种功能强大、易于使用和灵活的开发框架,它能够帮助开发者快速构建可靠和高效的企业级Java应用程序。 ### 回答3: Spring Framework 是一个Java平台上的开发框架,它提供了丰富的组件和功能,用于简化企业级应用程序的开发。它是基于IoC(控制反转)和AOP(面向切面编程)的原则,旨在提高开发者的生产力和应用程序的可维护性。 Spring Framework 提供了众多的模块,包括核心容器、数据访问/集成、Web开发、AOP和消息传递等。其中,核心容器模块提供了IoC容器,用于管理和组织应用程序的对象之间的依赖关系。开发者可以通过配置文件或注解来定义对象之间的依赖关系,减少了代码的耦合度。 另外,Spring Framework 还提供了一套强大的数据访问和集成模块,包括对各种数据源(如数据库、缓存、消息队列等)的支持。它提供了一个统一的数据访问层,使得开发者可以更加方便地进行数据库操作。 在Web开发方面,Spring Framework 提供了一个全功能的MVC框架,用于构建灵活且可扩展的Web应用程序。它支持多种视图技术,如JSP、Thymeleaf和Velocity等,并提供了处理表单、参数校验、文件上传等常用Web开发功能的集成。 此外,AOP模块允许开发者将横切关注点(如日志记录、事务管理等)从业务逻辑中独立出来,并通过切面进行统一管理。这大大减少了重复代码的编写,并提高了系统的可维护性和可扩展性。 总之,Spring Framework 是一个强大而灵活的开发框架,它帮助开发者简化了企业级应用程序的开发过程,提高了开发效率和代码质量。无论是大型企业应用程序还是小型Web应用程序,都可以从Spring Framework 中受益。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值