源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all

一、 项目结构说明

1.1 这里采用maven多模块的构建方式,在spring-boot-rabbitmq下构建三个子模块:

  1. rabbitmq-common 是公共模块,用于存放公共的接口、配置和bean,被rabbitmq-producer和rabbitmq-consumer在pom.xml中引用;
  2. rabbitmq-producer 是消息的生产者模块;
  3. rabbitmq-consumer是消息的消费者模块。

1.2 关于rabbitmq安装、交换机、队列、死信队列等基本概念可以参考我的手记《RabbitMQ实战指南》读书笔记,里面有详细的配图说明。

二、关键依赖

在父工程的项目中统一导入依赖rabbitmq的starter(spring-boot-starter-amqp),父工程的pom.xml如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <packaging>pom</packaging>

    <modules>
        <module>rabbitmq-consumer</module>
        <module>rabbitmq-producer</module>
        <module>rabbitmq-common</module>
    </modules>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.heibaiying</groupId>
    <artifactId>spring-boot-rabbitmq</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-boot-rabbitmq</name>
    <description>RabbitMQ project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

三、公共模块(rabbitmq-common)

  • bean 下为公共的实体类。
  • constant 下为公共配置,用静态常量引用。(这里我使用静态常量是为了方便引用,实际中也可以按照情况,抽取为公共配置文件)
package com.heibaiying.constant;

/**
 * @author : heibaiying
 * @description : rabbit 公用配置信息
 */
public class RabbitInfo {

    // queue 配置
    public static final String QUEUE_NAME = "spring.boot.simple.queue";
    public static final String QUEUE_DURABLE = "true";

    // exchange 配置
    public static final String EXCHANGE_NAME = "spring.boot.simple.exchange";
    public static final String EXCHANGE_TYPE = "topic";

    // routing key
    public static final String ROUTING_KEY = "springboot.simple.*";
}

四、服务消费者(rabbitmq-consumer)

4.1 消息消费者配置

spring:
  rabbitmq:
    addresses: 127.0.0.1:5672
    # RabbitMQ 默认的用户名和密码都是guest 而虚拟主机名称是 "/"
    # 如果配置其他虚拟主机地址,需要预先用管控台或者图形界面创建 图形界面地址 http://主机地址:15672
    username: guest
    password: guest
    virtual-host: /
    listener:
      simple:
        # 为了保证信息能够被正确消费,建议签收模式设置为手工签收,并在代码中实现手工签收
        acknowledge-mode: manual
        # 侦听器调用者线程的最小数量
        concurrency: 10
        # 侦听器调用者线程的最大数量
        max-concurrency: 50

4.2 使用注解@RabbitListener和@RabbitHandler创建消息监听者

  1. 使用注解创建的交换机、队列、和绑定关系会在项目初始化的时候自动创建,但是不会重复创建;
  2. 这里我们创建两个消息监听器,分别演示消息是基本类型和消息是对象时的配置区别。
/**
 * @author : heibaiying
 * @description : 消息是对象的消费者
 */

@Component
@Slf4j
public class RabbitmqBeanConsumer {

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = RabbitBeanInfo.QUEUE_NAME, durable = RabbitBeanInfo.QUEUE_DURABLE),
            exchange = @Exchange(value = RabbitBeanInfo.EXCHANGE_NAME, type = RabbitBeanInfo.EXCHANGE_TYPE),
            key = RabbitBeanInfo.ROUTING_KEY)
    )
    @RabbitHandler
    public void onMessage(@Payload Programmer programmer, @Headers Map<String, Object> headers, Channel channel) throws Exception {
        log.info("programmer:{} ", programmer);
        Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
        channel.basicAck(deliveryTag, false);
    }
}
@Component
@Slf4j
public class RabbitmqConsumer {

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = RabbitInfo.QUEUE_NAME, durable = RabbitInfo.QUEUE_DURABLE),
            exchange = @Exchange(value = RabbitInfo.EXCHANGE_NAME, type = RabbitInfo.EXCHANGE_TYPE),
            key = RabbitInfo.ROUTING_KEY)
    )
    @RabbitHandler
    public void onMessage(Message message, Channel channel) throws Exception {
        MessageHeaders headers = message.getHeaders();
        // 获取消息头信息和消息体
        log.info("msgInfo:{} ; payload:{} ", headers.get("msgInfo"), message.getPayload());
        //  DELIVERY_TAG 代表 RabbitMQ 向该Channel投递的这条消息的唯一标识ID,是一个单调递增的正整数
        Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
        // 第二个参数代表是否一次签收多条,当该参数为 true 时,则可以一次性确认 DELIVERY_TAG 小于等于传入值的所有消息
        channel.basicAck(deliveryTag, false);
    }

}

五、 消息生产者(rabbitmq-producer)

5.1 消息生产者配置

spring:
  rabbitmq:
    addresses: 127.0.0.1:5672
    # RabbitMQ 默认的用户名和密码都是guest 而虚拟主机名称是 "/"
    # 如果配置其他虚拟主机地址,需要预先用管控台或者图形界面创建 图形界面地址 http://主机地址:15672
    username: guest
    password: guest
    virtual-host: /
    # 是否启用发布者确认 具体确认回调实现见代码
    publisher-confirms: true
    # 是否启用发布者返回 具体返回回调实现见代码
    publisher-returns: true
    # 是否启用强制消息 保证消息的有效监听
    template.mandatory: true

server:
  port: 8090

5.2 创建消息生产者

/**
 * @author : heibaiying
 * @description : 消息生产者
 */
@Component
@Slf4j
public class RabbitmqProducer {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void sendSimpleMessage(Map<String, Object> headers, Object message,
                                  String messageId, String exchangeName, String key) {
        // 自定义消息头
        MessageHeaders messageHeaders = new MessageHeaders(headers);
        // 创建消息
        Message<Object> msg = MessageBuilder.createMessage(message, messageHeaders);
        /* 确认的回调 确认消息是否到达 Broker 服务器 其实就是是否到达交换器
           如果发送时候指定的交换器不存在 ack就是false 代表消息不可达 */
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            log.info("correlationData:{} , ack:{}", correlationData.getId(), ack);
            if (!ack) {
                System.out.println("进行对应的消息补偿机制");
            }
        });
        /* 消息失败的回调
         * 例如消息已经到达交换器上,但路由键匹配任何绑定到该交换器的队列,会触发这个回调,此时 replyText: NO_ROUTE
         */
        rabbitTemplate.setReturnCallback((message1, replyCode, replyText, exchange, routingKey) -> {
            log.info("message:{}; replyCode: {}; replyText: {} ; exchange:{} ; routingKey:{}",
                    message1, replyCode, replyText, exchange, routingKey);
        });
        // 在实际中ID 应该是全局唯一 能够唯一标识消息 消息不可达的时候触发ConfirmCallback回调方法时可以获取该值,进行对应的错误处理
        CorrelationData correlationData = new CorrelationData(messageId);
        rabbitTemplate.convertAndSend(exchangeName, key, msg, correlationData);
    }
}

5.3 以单元测试的方式发送消息

@RunWith(SpringRunner.class)
@SpringBootTest
public class RabbitmqProducerTests {

    @Autowired
    private RabbitmqProducer producer;

    /***
     * 发送消息体为简单数据类型的消息
     */
    @Test
    public void send() {
        Map<String, Object> heads = new HashMap<>();
        heads.put("msgInfo", "自定义消息头信息");
        // 模拟生成消息ID,在实际中应该是全局唯一的 消息不可达时候可以在setConfirmCallback回调中取得,可以进行对应的重发或错误处理
        String id = String.valueOf(Math.round(Math.random() * 10000));
        producer.sendSimpleMessage(heads, "hello Spring", id, RabbitInfo.EXCHANGE_NAME, "springboot.simple.abc");
    }

    /***
     * 发送消息体为bean的消息
     */
    @Test
    public void sendBean() {
        String id = String.valueOf(Math.round(Math.random() * 10000));
        Programmer programmer = new Programmer("xiaoMing", 12, 12123.45f, new Date());
        producer.sendSimpleMessage(null, programmer, id, RabbitBeanInfo.EXCHANGE_NAME, RabbitBeanInfo.ROUTING_KEY);
    }

}

六、项目构建的说明

因为在项目中,consumer和producer模块均依赖公共模块,所以在构建consumer和producer项目前需要将common 模块安装到本地仓库,依次父工程common模块执行:

mvn install -Dmaven.test.skip = true

consumer中 pom.xml如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.heibaiying</groupId>
        <artifactId>spring-boot-rabbitmq</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <artifactId>rabbitmq-consumer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>rabbitmq-consumer</name>
    <description>RabbitMQ consumer project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.heibaiying</groupId>
            <artifactId>rabbitmq-common</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

producer中 pom.xml如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.heibaiying</groupId>
        <artifactId>spring-boot-rabbitmq</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <artifactId>rabbitmq-producer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>rabbitmq-producer</name>
    <description>RabbitMQ producer project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.heibaiying</groupId>
            <artifactId>rabbitmq-common</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

附:源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all

spring boot 2.x 系列 —— spring boot 整合 RabbitMQ的更多相关文章

  1. spring boot实战(第十二篇)整合RabbitMQ

    前言 最近几篇文章将围绕消息中间件RabbitMQ展开,对于RabbitMQ基本概念这里不阐述,主要讲解RabbitMQ的基本用法.Java客户端API介绍.spring Boot与RabbitMQ整 ...

  2. spring boot 2.x 系列 —— spring boot 整合 redis

    文章目录 一.说明 1.1 项目结构 1.2 项目主要依赖 二.整合 Redis 2.1 在application.yml 中配置redis数据源 2.2 封装redis基本操作 2.3 redisT ...

  3. spring boot 2.x 系列 —— spring boot 整合 druid+mybatis

    源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.说明 1.1 项目结构 项目查询用的表对应的建表语句放置在resour ...

  4. spring boot 2.x 系列 —— spring boot 整合 servlet 3.0

    文章目录 一.说明 1.1 项目结构说明 1.2 项目依赖 二.采用spring 注册方式整合 servlet 2.1 新建过滤器.监听器和servlet 2.2 注册过滤器.监听器和servlet ...

  5. spring boot 2.x 系列 —— spring boot 整合 kafka

    文章目录 一.kafka的相关概念: 1.主题和分区 2.分区复制 3. 生产者 4. 消费者 5.broker和集群 二.项目说明 1.1 项目结构说明 1.2 主要依赖 二. 整合 kafka 2 ...

  6. spring boot 2.x 系列 —— spring boot 整合 dubbo

    文章目录 一. 项目结构说明 二.关键依赖 三.公共模块(boot-dubbo-common) 四. 服务提供者(boot-dubbo-provider) 4.1 提供方配置 4.2 使用注解@Ser ...

  7. spring boot 2.x 系列 —— spring boot 实现分布式 session

    文章目录 一.项目结构 二.分布式session的配置 2.1 引入依赖 2.2 Redis配置 2.3 启动类上添加@EnableRedisHttpSession 注解开启 spring-sessi ...

  8. 2018年分享的Spring Cloud 2.x系列文章

    还有几个小时2018年就要过去了,盘点一下小编从做做公众号以来发送了273篇文章,其中包含原创文章90篇,虽然原创的有点少,但是2019年小编将一如既往给大家分享跟多的干货,分享工作中的经验,让大家在 ...

  9. spring boot&&cloud干货系列

    接触spring boot也有些时日了,刚开始博主还想参照官方参考指南自己写一个系列的入门式的教程,包含spring boot的所有模块的用法,后来发现,有一大波优秀的系列文章和项目了,所以就没班门弄 ...

随机推荐

  1. Android中WebView的相关使用

    近期做的项目中,遇到个非常棘手的问题: 客户给我的数据是有限制的,因此,在返回某条详细页面内容的时候,他仅仅能给我一个html片段,里面包括 文字,图片以及附件的下载地址.假设网页模版规范的爱比較好说 ...

  2. Linux性能测试 dmesg命令

    dmesg 命令主要用来显示内核信息.使用 dmesg 可以有效诊断机器硬件故障或者添加硬件出现的问题.  另外,使用 dmesg 可以确定您的服务器安装了那些硬件.每次系统重启,系统都会检查所有硬件 ...

  3. WPF 走马灯 文字滚动 自定义控件

    原文:WPF 走马灯 文字滚动 自定义控件 /// <summary> /// Label走马灯自定义控件 /// </summary> [ToolboxBitmap(type ...

  4. zcelib - One cplusplus C++ crossplatform library use for develop server,similar to ACE.

    zcelib - One cplusplus C++ crossplatform library use for develop server,similar to ACE.OS适配层,为了适应WIN ...

  5. cocos2d-x 在XML分析和数据存储

    无意中起到一周中的游戏,哎,时间过得总是打得那么快时,. .. 于是今天决定看一下之前不怎么非常熟悉的XML;(之前做游戏时数据的储存用到过XML.但这块是还有一个同事在做,所以不怎么熟悉), 看了看 ...

  6. 用C语言编写Windows服务程序的五个步骤

    Windows 服务被设计用于需要在后台运行的应用程序以及实现没有用户交互的任务.为了学习这种控制台应用程序的基础知识,C(不是C++)是最佳选择.本文将建立并实现一个简单的服务程序,其功能是查询系统 ...

  7. 微信nodejs开发模块指南

    1.微信消息处理 node-weixin-message wechat 2.微信加密 node-weixin-crypto wechat-crypto 3.微信支付 node-weixin-pay w ...

  8. Symbol not found: _lua_objlen

    lua: error loading module 'cjson' from file '/usr/local/lib/lua/5.3/cjson.so': dlopen(/usr/local/lib ...

  9. WPF特效-绘制实时2D激光雷达图

    原文:WPF特效-绘制实时2D激光雷达图 接前两篇: https://blog.csdn.net/u013224722/article/details/80738619 https://blog.cs ...

  10. laravel在wamp中输入地址后总是无法访问

    在wamp中的apache中conf的httpd.conf #LoadModule rewrite_module modules/mod_rewrite.so 改为 LoadModule rewrit ...