JMS的全称是Java Message Service,即Java消息服务。它主要用于在生产者和消费者之间进行消息传递,生产者负责产生消息,而消费者负责接收消息。把它应用到实际的业务需求中的话咱们能够在特定的时候利用生产者生成一消息,并进行发送,对应的消费者在接收到对应的消息后去完成对应的业务逻辑。对于消息的传递有两种类型,一种是点对点的,即一个生产者和一个消费者一一对应;另外一种是发布/订阅模式,即一个生产者产生消息并进行发送后,能够由多个消费者进行接收。 html
对JMS作了一个简要介绍以后,接下来就讲一下Spring整合JMS的具体过程。JMS只是一个标准,真正在使用它的时候咱们须要有它的具体实现,这里咱们就使用Apache的activeMQ来做为它的实现。所使用的依赖利用Maven来进行管理,具体依赖以下: java
既然是使用的apache的activeMQ做为JMS的实现,那么首先咱们应该到apache官网上下载activeMQ(http://activemq.apache.org/download.html),进行解压后运行其bin目录下面的activemq.bat文件启动activeMQ。 spring
ConnectionFactory是用于产生到JMS服务器的连接的,Spring为咱们提供了多个ConnectionFactory,有SingleConnectionFactory和CachingConnectionFactory。SingleConnectionFactory对于创建JMS服务器连接的请求会一直返回同一个连接,而且会忽略Connection的close方法调用。CachingConnectionFactory继承了SingleConnectionFactory,因此它拥有SingleConnectionFactory的全部功能,同时它还新增了缓存功能,它能够缓存Session、MessageProducer和MessageConsumer。这里咱们使用SingleConnectionFactory来做为示例。 apache
这样就定义好产生JMS服务器连接的ConnectionFactory了吗?是非也。Spring提供的ConnectionFactory只是Spring用于管理ConnectionFactory的,真正产生到JMS服务器连接的ConnectionFactory还得是由JMS服务厂商提供,而且须要把它注入到Spring提供的ConnectionFactory中。咱们这里使用的是ActiveMQ实现的JMS,因此在咱们这里真正的能够产生Connection的就应该是由ActiveMQ提供的ConnectionFactory。因此定义一个ConnectionFactory的完整代码应该以下所示: api
ActiveMQ为咱们提供了一个PooledConnectionFactory,经过往里面注入一个ActiveMQConnectionFactory能够用来将Connection、Session和MessageProducer池化,这样能够大大的减小咱们的资源消耗。当使用PooledConnectionFactory时,咱们在定义一个ConnectionFactory时应该是以下定义: 缓存
配置好ConnectionFactory以后咱们就须要配置生产者。生产者负责产生消息并发送到JMS服务器,这一般对应的是咱们的一个业务逻辑服务实现类。可是咱们的服务实现类是怎么进行消息的发送的呢?这一般是利用Spring为咱们提供的JmsTemplate类来实现的,因此配置生产者其实最核心的就是配置进行消息发送的JmsTemplate。对于消息发送者而言,它在发送消息的时候要知道本身该往哪里发,为此,咱们在定义JmsTemplate的时候须要往里面注入一个Spring提供的ConnectionFactory对象。 服务器
在真正利用JmsTemplate进行消息发送的时候,咱们须要知道消息发送的目的地,即destination。在Jms中有一个用来表示目的地的Destination接口,它里面没有任何方法定义,只是用来作一个标识而已。当咱们在使用JmsTemplate进行消息发送时没有指定destination的时候将使用默认的Destination。默认Destination能够经过在定义jmsTemplate bean对象时经过属性defaultDestination或defaultDestinationName来进行注入,defaultDestinationName对应的就是一个普通字符串。在ActiveMQ中实现了两种类型的Destination,一个是点对点的ActiveMQQueue,另外一个就是支持订阅/发布模式的ActiveMQTopic。在定义这两种类型的Destination时咱们均可以经过一个name属性来进行构造,如: session
假设咱们定义了一个ProducerService,里面有一个向Destination发送纯文本消息的方法sendMessage,那么咱们的代码就大概是这个样子: 并发
咱们能够看到在sendMessage方法体里面咱们是经过jmsTemplate来发送消息到对应的Destination的。到此,咱们生成一个简单的文本消息并把它发送到指定目的地Destination的生产者就配置好了。 app
生产者往指定目的地Destination发送消息后,接下来就是消费者对指定目的地的消息进行消费了。那么消费者是如何知道有生产者发送消息到指定目的地Destination了呢?这是经过Spring为咱们封装的消息监听容器MessageListenerContainer实现的,它负责接收信息,并把接收到的信息分发给真正的MessageListener进行处理。每一个消费者对应每一个目的地都须要有对应的MessageListenerContainer。对于消息监听容器而言,除了要知道监听哪一个目的地以外,还须要知道到哪里去监听,也就是说它还须要知道去监听哪一个JMS服务器,这是经过在配置MessageConnectionFactory的时候往里面注入一个ConnectionFactory来实现的。因此咱们在配置一个MessageListenerContainer的时候有三个属性必须指定,一个是表示从哪里监听的ConnectionFactory;一个是表示监听什么的Destination;一个是接收到消息之后进行消息处理的MessageListener。Spring一共为咱们提供了两种类型的MessageListenerContainer,SimpleMessageListenerContainer和DefaultMessageListenerContainer。
SimpleMessageListenerContainer会在一开始的时候就建立一个会话session和消费者Consumer,而且会使用标准的JMS MessageConsumer.setMessageListener()方法注册监听器让JMS提供者调用监听器的回调函数。它不会动态的适应运行时须要和参与外部的事务管理。兼容性方面,它很是接近于独立的JMS规范,但通常不兼容Java EE的JMS限制。
大多数状况下咱们仍是使用的DefaultMessageListenerContainer,跟SimpleMessageListenerContainer相比,DefaultMessageListenerContainer会动态的适应运行时须要,而且可以参与外部的事务管理。它很好的平衡了对JMS提供者要求低、先进功能如事务参与和兼容Java EE环境。
定义处理消息的MessageListener
要定义处理消息的MessageListener咱们只须要实现JMS规范中的MessageListener接口就能够了。MessageListener接口中只有一个方法onMessage方法,当接收到消息的时候会自动调用该方法。
有了MessageListener以后咱们就能够在Spring的配置文件中配置一个消息监听容器了。
咱们能够看到咱们定义了一个名叫queue的ActiveMQQueue目的地,咱们的监听器就是监听了发送到这个目的地的消息。
至此咱们的生成者和消费者都配置完成了,这也就意味着咱们的整合已经完成了。这个时候完整的Spring的配置文件应该是这样的:
接着咱们来测试一下,看看咱们的整合是否真的成功了,测试代码以下:
在上面的测试代码中咱们利用生产者发送了两个消息,正常来讲,消费者应该能够接收到这两个消息。运行测试代码后控制台输出以下:
看,控制台已经进行了正确的输出,这说明咱们的整合确实是已经成功了。