您当前的位置: 首页 >  文章详情 网站首页 文章详情

ActiveMQ学习(四)Spring整合ActiveMQ

发布时间:2018-4-11 11:46:16 作者:Jastar · Wang 浏览:1332

因为2018年的第一场雪,比以往时候来的更晚一些,所以,本篇文章隔了近5个月才更新,抱歉来的有点晚了各位,不是人造革,皮是真的皮,啊弥陀佛,罪过罪过……本篇,将继续跟随以往的脚步,使用Spring MVC+ActiveMQ+Maven+Tomcat,做一个整合的简单实例。

1. 开发环境

1.1 版本工具

  • Spring 4.1.8

  • ActiveMQ 5.14.5

  • JDK 1.7

  • Tomcat 7

  • Eclipse Mars+Maven

  • ActiveMQ服务已经启动

1.2 项目结构

这里写图片描述

1.3 Maven依赖

推荐使用介个:

<!-- ActiveMQ -->
<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-spring</artifactId>
    <version>5.14.5</version>
</dependency>


不推荐使用介个(FAQ中说明):

<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-all</artifactId>
    <version>5.14.5</version>
</dependency>


2. 项目配置

为了简单粗暴及猿友们易懂,我就直接上代码了,代码中有详细的注释,重要的地方我也会在文章中指出。

2.1 配置AMQ(spring-amq.xml)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:amq="http://activemq.apache.org/schema/core"
    xmlns:jms="http://www.springframework.org/schema/jms"
    xsi:schemaLocation="http://www.springframework.org/schema/beans   
        http://www.springframework.org/schema/beans/spring-beans-4.1.xsd   
        http://www.springframework.org/schema/context   
        http://www.springframework.org/schema/context/spring-context-4.1.xsd
        http://www.springframework.org/schema/jms
        http://www.springframework.org/schema/jms/spring-jms-4.1.xsd
        http://activemq.apache.org/schema/core
        http://activemq.apache.org/schema/core/activemq-core-5.14.5.xsd">

    <!-- 1、定义ActiveMQ服务厂商提供的连接工厂 ,这才是真正实现JMS的 -->
    <amq:connectionFactory id="amqConnectionFactory"
        brokerURL="tcp://localhost:61616" userName="admin" password="admin" />

    <!-- 2、定义Spring内部的连接工厂,并引用上面的AMQ的连接工厂; Spring使用CachingConnectionFactory来管理实际的AMQ工厂 -->
    <bean id="connectionFactory"
        class="org.springframework.jms.connection.CachingConnectionFactory">
        <!-- 通过此属性引用AMQ的连接工厂 -->
        <property name="targetConnectionFactory" ref="amqConnectionFactory"></property>
        <!-- 也可以这样 -->
        <!-- <constructor-arg ref="amqConnectionFactory" /> -->
        <!-- 配置Session缓存数量 -->
        <property name="sessionCacheSize" value="100" />
    </bean>

    <!-- 3、定义JmsTemplate的Queue类型 -->
    <bean id="jmsQueueTemplate" class="org.springframework.jms.core.JmsTemplate">
        <!-- 这个connectionFactory对应的是我们定义的Spring提供的那个ConnectionFactory对象 -->
        <constructor-arg ref="connectionFactory" />
        <!-- false,表示非pub/sub模型(发布/订阅),即队列 -->
        <property name="pubSubDomain" value="false" />
    </bean>

    <!-- 4、定义JmsTemplate的Topic类型 -->
    <bean id="jmsTopicTemplate" class="org.springframework.jms.core.JmsTemplate">
        <!-- 这个connectionFactory对应的是我们定义的Spring提供的那个ConnectionFactory对象 -->
        <constructor-arg ref="connectionFactory" />
        <!-- true,表示pub/sub模型(发布/订阅) -->
        <property name="pubSubDomain" value="true" />
    </bean>

    <!-- 5、定义Queue监听器 -->
    <jms:listener-container destination-type="queue"
        container-type="default" connection-factory="connectionFactory"
        acknowledge="auto">
        <jms:listener destination="my.queue" ref="queueReceiver1" />
        <jms:listener destination="my.queue" ref="queueReceiver2" />
    </jms:listener-container>

    <!-- 6、定义Topic监听器 -->
    <jms:listener-container destination-type="topic"
        container-type="default" connection-factory="connectionFactory"
        acknowledge="auto">
        <jms:listener destination="my.topic" ref="topicReceiver1" />
        <jms:listener destination="my.topic" ref="topicReceiver2" />
    </jms:listener-container>

</beans>

来,看黑板,敲重点:

(1)首先配置AMQ的连接工厂,在上篇文章的代码中,我们首先创建的就是此对象。

(2)配置Spring内部的连接工厂,主要是对AMQ的工厂进行了封装,便于管理;Spring提供了多种连接工厂,介绍如下两个:

  • SingleConnectionFactory

    对于建立JMS服务器链接的请求会一直返回同一个链接,并且会忽略Connection的close方法调用。

  • CachingConnectionFactory

    继承了SingleConnectionFactory,拥有前者的所有功能,同时它新增了缓存,可以提升效率,它和AMQ的PooledConnectionFactory都是比较推荐的。

(3)配置生产者

  • 在Spring中,我们不再使用AMQ的原生对象进行消息的发送,而是使用Spring提供的一个模板类,当当当当——JmsTemplate。它就相当于我们之前使用过的HibernateTemplate,所以,配置生产者最核心的就是配置JmsTemplate

  • 对于消息发送者而言,它在发送消息的时候要知道自己该往哪里发,为此,我们在定义JmsTemplate的时候需要注入一个Spring提供的ConnectionFactory对象。

  • 另外,配置JmsTemplate时,需要知道发送哪种类型的消息,一是点对点,二是订阅/发布,表现出来就是通过JmsTemplatepubSubDomain属性来定义。

(4)配置消费者

  • 在实际使用中,我们一般不使用消费者对象去手动获取消息,而是通过消息监听器(MessageListenerContainer)来实现,通过destination属性来指定其要监听的目的地。

  • 除了监听目的地之外,还需要知道到哪里监听,所以指定一个connection-factory就是理所应当的了。

  • 另外就是监听器对应我们的实际处理类,通过ref进行引用。

  • 推荐使用DefaultMessageListenerContainer,它允许异步接收消息并缓存session和消息consumer,而且还可以根据消息数量动态的增加或缩减监听器的数量。

2.2 配置Spring MVC

除了spring-amq.xml是重中之重,其他的都没有什么特别的配置,在此不再做详细说明,更多配置请查看源码。

(1)spring-main.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-4.1.xsd   
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context-4.1.xsd   
       http://www.springframework.org/schema/aop 
       http://www.springframework.org/schema/aop/spring-aop-4.1.xsd   
       http://www.springframework.org/schema/tx 
       http://www.springframework.org/schema/tx/spring-tx-4.1.xsd">

    <!-- 扫描组件 -->
    <context:component-scan base-package="com.jastar.demo.amq" />

</beans>

(2)spring-mvc.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="   
                http://www.springframework.org/schema/beans   
                http://www.springframework.org/schema/beans/spring-beans.xsd   
                http://www.springframework.org/schema/context   
                http://www.springframework.org/schema/context/spring-context-4.1.xsd   
                http://www.springframework.org/schema/mvc   
                http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd">

    <!-- 扫描controller -->
    <context:component-scan base-package="com.jastar.demo.ctrl" />

    <mvc:annotation-driven />

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/res/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
</beans>

3. 编写代码

同样,大部分代码较为简单,在此只展示部分,更多请查看源码。

3.1 消息生产者

QueueSender.java:

package com.jastar.demo.amq.producer;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Component;

/**
 * 队列消息生产者
 * 
 * @author Jastar·Wang
 * @date 2018年4月4日
 * @since 1.0
 */
@Component
public class QueueSender {

    @Autowired
    @Qualifier("jmsQueueTemplate")
    private JmsTemplate jmsTemplate;

    /**
     * 发送一条消息到指定的队列(目标)
     * 
     * @param queueName
     *            队列名称
     * @param message
     *            消息内容
     */
    public void send(String queueName, final String message) {
        jmsTemplate.send(queueName, new MessageCreator() {
            @Override
            public Message createMessage(Session session) throws JMSException {
                // 其他的还有createXXXMessage(...)
                return session.createTextMessage(message);
            }
        });
    }

}

3.2 消息消费者

QueueReceiver1.java:

package com.jastar.demo.amq.consumer.queue;

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

import org.springframework.stereotype.Component;

/**
 * 队列消息消费者1
 * 
 * @author Jastar·Wang
 * @date 2018年4月4日
 * @since 1.0
 */
@Component
public class QueueReceiver1 implements MessageListener {

    @Override
    public void onMessage(Message message) {
        try {
            /*
             * 实际项目中拿到String类型的message(通常是JSON字符串)之后,会进行反序列化成对象,做进一步的处理
             */
            System.out.println("QueueReceiver1接收到消息:" + ((TextMessage) message).getText());
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }
}

4. 测试

Pass、过、要不起……

港真,私下已测试success,在此就不再放到这里来说了,运行项目访问首页即可,傻瓜式操作。

5. FAQ

5.1 关于AMQ的jar包依赖

答:市面上出现了使用activemq-all.jar和不使用它的方式(如我开头提到的),在这里,我个人推荐使用“activemq-spring”的形式,因为:

  • activemq-all.jar中整合了很多的东西,例如Spring,如果再引用Spring本身的话,可能会导致jar包冲突而出错,另外,还整合了其他一系列框架。(整合Spring是从activemq-all.jar的5.12.0的版本开始的,其他的就不知道了)

  • activemq-all.jar足足有15M大,而需要什么引用什么顶多了几M,单看这点,滋滋滋……

5.2 关于spring-amq.xml的配置形式

答:市面上同样存在着两种配置形式,一种是使用amq和jms形式的标签(本文即是),另一种是使用spring的传统bean的配置形式,虽然配置不同,但两者效果都一样,都正确,不过个人觉得前者略简单,不过需要注意引用namespace:

http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms-4.1.xsd
http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core-5.14.5.xsd

5.3 关于本文

答:博主菜鸟一只,本文的部分内容及大部分代码都是参考csdn于亮 大神的文章,包括JSP页面,没懒得改,项目使用了maven进行升级,对理论部分略有完善,在此只作为学习总结使用。

5.4 源码

传送门:戳我戳我


…… 



“纸上得来终觉浅,绝知此事要躬行。——鲁迅”

“鲁迅:这话我真没说过。” 



……


原创声明

1.本文章系原创,版权归本站所有。

2.本站所有文章允许转载,开放分享,但严禁用于任何商业用途。

3.转载文章请务必保留以下信息:
 原文作者:Jastar·Wang(或“代码与酒博客频道”)
 原文链接: