rabbitmq学习之路(二)spring的集成方式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qiyongkang520/article/details/60603033

今天来给大家介绍下rabbitmq的spring集成方式,现在绝大部分的组件基本上都能够与spring无缝集成,使用起来也非常方便。
下面,笔者分以下几个步骤进行介绍:

一、maven依赖

pom.xml依赖如下:

<!-- RabbitMQ -->
    <dependency>
        <groupId>com.rabbitmq</groupId>
        <artifactId>amqp-client</artifactId>
        <version>3.3.4</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.amqp</groupId>
        <artifactId>spring-rabbit</artifactId>
        <version>1.4.5.RELEASE</version>
    </dependency>

注意对于此版本的rabbitmq使用的spring版本是4.1.6,否则会解析报错的。

二、服务器配置rabbitmq.properties

rabbitmq服务器的配置rabbitmq.properties如下:

mq.host=127.0.0.1
mq.username=admin
mq.password=888888
mq.port=5672
# 前缀
mq.queue=qyk

注意rabbitmq的默认web访问端口是15672,而连接的端口号是5672,不要搞错了;当然你也可以修改这些默认配置~

三、spring集成配置如下

rabbitmqContext.xml配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop" 
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:rabbit="http://www.springframework.org/schema/rabbit"
    xsi:schemaLocation="
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/rabbit
        http://www.springframework.org/schema/rabbit/spring-rabbit-1.0.xsd
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util-3.0.xsd">
    <!-- 属性文件 -->
    <util:properties id="appConfig" location="classpath:rabbitmq.properties"/>

    <!-- 连接配置 -->
    <rabbit:connection-factory id="connectionFactory" host="${mq.host}" username="${mq.username}"
        password="${mq.password}" port="${mq.port}"/>

    <rabbit:admin connection-factory="connectionFactory"/>

    <!-- 消息队列客户端 -->
    <rabbit:template id="amqpTemplate" exchange="${mq.queue}_exchange" connection-factory="connectionFactory"/>

    <!-- queue 队列声明 -->
    <!-- 
        durable 是否持久化 
        exclusive 仅创建者可以使用的私有队列,断开后自动删除 
        auto-delete 当所有消费端连接断开后,是否自动删除队列 -->
    <rabbit:queue id="test_queue" name="${mq.queue}_testQueue" durable="true" auto-delete="false" exclusive="false" />

    <!-- 交换机定义 -->
    <!-- 交换机:一个交换机可以绑定多个队列,一个队列也可以绑定到多个交换机上。如果没有队列绑定到交换机上,则发送到该交换机上的信息则会丢失。
      **交换机的四种模式:
      direct:转发消息到 routigKey 指定的队列。
      topic:按规则转发消息(最灵活)。
      headers:这个用得少
      fanout:转发消息到所有绑定队列
     -->
    <rabbit:topic-exchange name="${mq.queue}_exchange" durable="true" auto-delete="false">
        <rabbit:bindings>
            <!-- 设置消息Queue匹配的pattern (direct模式为key) -->
            <rabbit:binding queue="test_queue" pattern="${mq.queue}_pattern"/>
        </rabbit:bindings>
    </rabbit:topic-exchange>

    <!-- 配置监听 消费者 -->
    <bean name="rabbitmqConsumer" class="org.qiyongkang.spring.rabbitmq.Consumer"></bean>
    <rabbit:listener-container connection-factory="connectionFactory" acknowledge="auto">
        <!-- 
            queues 监听队列,多个用逗号分隔 
            ref 监听器 -->
        <rabbit:listener queues="test_queue" ref="rabbitmqConsumer"/>
    </rabbit:listener-container>
</beans>

这里注意,相关的命名空间需要引入进来!
这里面配置了一个消费者Consumer,如下:

/**
 * Project Name:qyk_testSpring
 * File Name:Consumer.java
 * Package Name:org.qiyongkang.spring.rabbitmq
 * Date:2017年3月6日上午10:22:58
 * Copyright (c) 2017, Thinkive(http://www.thinkive.com/) All Rights Reserved.
 *
*/

package org.qiyongkang.spring.rabbitmq;

import java.util.Map;

import org.qiyongkang.spring.util.SerializeUtil;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;

/**
 * ClassName:Consumer <br/>
 * Function: TODO ADD FUNCTION. <br/>
 * Reason: TODO ADD REASON. <br/>
 * Date:     2017年3月6日 上午10:22:58 <br/>
 * @author   qiyongkang
 * @version
 * @since    JDK 1.6
 * @see
 */
public class Consumer implements MessageListener {

    @SuppressWarnings("unchecked")
    @Override
    public void onMessage(Message message) {
        Map<String, Object> content = (Map<String, Object>) SerializeUtil.toObject(message.getBody());
        System.out.println("消费内容:" + content);
    }

}

这里因为把消息对象放进去的时候是默认会序列化的,所以这里进行反序列化,SerializeUtil如下:

/**
 * Project Name:qyk_testSpring
 * File Name:SerializeUtil.java
 * Package Name:org.qiyongkang.spring.util
 * Date:2017年3月6日下午3:06:09
 * Copyright (c) 2017, Thinkive(http://www.thinkive.com/) All Rights Reserved.
 *
*/

package org.qiyongkang.spring.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * ClassName:SerializeUtil <br/>
 * Function: TODO ADD FUNCTION. <br/>
 * Reason: TODO ADD REASON. <br/>
 * Date: 2017年3月6日 下午3:06:09 <br/>
 * 
 * @author qiyongkang
 * @version
 * @since JDK 1.6
 * @see
 */
public class SerializeUtil {
    /**
     * 对象转数组
     * 
     * @param obj
     * @return
     */
    public static byte[] toByteArray(Object obj) {
        byte[] bytes = null;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(obj);
            oos.flush();
            bytes = bos.toByteArray();
            oos.close();
            bos.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return bytes;
    }

    /**
     * 数组转对象
     * 
     * @param bytes
     * @return
     */
    public static Object toObject(byte[] bytes) {
        Object obj = null;
        try {
            ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
            ObjectInputStream ois = new ObjectInputStream(bis);
            obj = ois.readObject();
            ois.close();
            bis.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        }
        return obj;
    }
}

另外,属性文件的加载是放在applicationContext.xml中,如下:

<!-- properties config   -->  
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
      <property name="order" value="1"/>  
      <property name="ignoreUnresolvablePlaceholders" value="true"/>  
      <property name="locations">  
        <list> 
            <value>classpath:rabbitmq.properties</value>
        </list>  
      </property>  
    </bean>

    <!-- rabbitmq 缓存 -->
    <import resource="rabbitmqContext.xml"/>

    <!-- 定义扫描的包路劲 -->
    <context:component-scan base-package="org.qiyongkang.spring.**" />

然后,我们再准备一个生产者Producer,如下:

/**
 * Project Name:qyk_testSpring
 * File Name:Producer.java
 * Package Name:org.qiyongkang.spring.rabbitmq
 * Date:2017年3月6日上午10:22:49
 * Copyright (c) 2017, Thinkive(http://www.thinkive.com/) All Rights Reserved.
 *
*/

package org.qiyongkang.spring.rabbitmq;

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * ClassName:Producer <br/>
 * Function: TODO ADD FUNCTION. <br/>
 * Reason: TODO ADD REASON. <br/>
 * Date:     2017年3月6日 上午10:22:49 <br/>
 * @author   qiyongkang
 * @version
 * @since    JDK 1.6
 * @see
 */
@Service
public class Producer {
    @Autowired
    private AmqpTemplate amqpTemplate;

    public void sendQueue(String exchange_key, String queue_key, Object object) {
        // convertAndSend 将Java对象转换为消息发送至匹配key的交换机中Exchange
        amqpTemplate.convertAndSend(exchange_key, queue_key, object);
    }
}

这里消费和生产的逻辑都非常简单,生产者不断给转换器发消息,然后路由选择相应的队列由消费者进行处理,关于转换器相关的概念笔者在后面进行介绍。

四、测试类

这里,我们准备一个spring的测试类,如下:

/**
 * Project Name:qyk_testSpring
 * File Name:ProducerTest.java
 * Package Name:org.qiyongkang.spring.rabbitmq
 * Date:2017年3月6日上午10:47:36
 * Copyright (c) 2017, Thinkive(http://www.thinkive.com/) All Rights Reserved.
 *
*/

package org.qiyongkang.spring.rabbitmq;

import java.util.HashMap;
import java.util.Map;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 * ClassName:ProducerTest <br/>
 * Function: TODO ADD FUNCTION. <br/>
 * Reason: TODO ADD REASON. <br/>
 * Date:     2017年3月6日 上午10:47:36 <br/>
 * @author   qiyongkang
 * @version
 * @since    JDK 1.6
 * @see
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class ProducerTest extends AbstractJUnit4SpringContextTests {
    @Autowired
    private Producer producer;

    @Value("#{appConfig['mq.queue']}")
    private String queueId;

    @Test
    public void testSendQueue() {
        try {
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("name", "qiyongkang");
            //指定转换器以及路由key,就会被绑定相应路由key的消费者进行消费处理
            producer.sendQueue(queueId + "_exchange", queueId + "_pattern", map);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

好了,所以的配置以及代码已经写好了,我们来进行测试看看。
运行测试类,可以看到控制台输出如下:
这里写图片描述
然后,看看web控制台,可以看到已经生产了相应的转换器和队列,如下:
这里写图片描述
这里写图片描述
好了,关于rabbitmq的集成就到了这儿了,配置起来还是比较清晰明了的~~

猜你喜欢

转载自blog.csdn.net/qiyongkang520/article/details/60603033
今日推荐