Spring 整合 RabbitMQ

Stella981
• 阅读 650

1.导入依赖

<properties>

    .....

    <!-- spring -->
    <spring.version>5.1.1.RELEASE</spring.version>
    <!-- log4j日志包版本号 -->
    <slf4j.version>1.7.18</slf4j.version>
    <log4j.version>1.2.17</log4j.version>
  </properties>

  <dependencies>

    <!-- Spring -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-oxm</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context-support</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <!-- AOP-AspectJ spring-aop依赖 -->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>1.8.6</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.6</version>
    </dependency>

    <!-- 添加日志相关jar包 -->
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>${log4j.version}</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>${slf4j.version}</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>${slf4j.version}</version>
    </dependency>

    <!-- rabbitmq -->
    <dependency>
      <groupId>org.springframework.amqp</groupId>
      <artifactId>spring-rabbit</artifactId>
      <version>1.7.5.RELEASE</version>
    </dependency>

    .....

  </dependencies>

2.创建配置文件

  a.创建 spring.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:aop="http://www.springframework.org/schema/aop"
       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/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 自动扫描的包名 -->
    <context:component-scan base-package="com.wode" />

    <!-- 开启AOP代理 -->
    <aop:aspectj-autoproxy proxy-target-class="true" />

    <!--开启注解处理器 -->
    <context:annotation-config>
    </context:annotation-config>

    <context:property-placeholder location="classpath:rabbit.properties"/>
    <!-- Spring中引入其他配置文件 -->
    <import resource="classpath*:/spring-rabbit.xml" />

</beans>

  b.创建 spring-rabbit.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:rabbit="http://www.springframework.org/schema/rabbit"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit-1.2.xsd">

    <!-- ============================================公共部分============================================ -->

    <!-- 创建连接类 连接安装好的 rabbitmq -->
    <rabbit:connection-factory id="connectionFactory" host="${rabbit.ip}" port="${rabbit.port}" username="${rabbit.username}" password="${rabbit.password}" />
    <rabbit:admin connection-factory="connectionFactory"/>

    <!-- spring amqp默认的是jackson 的一个插件,目的将生产者生产的数据转换为json存入消息队列 -->
    <bean id="jsonMessageConverter" class="org.springframework.amqp.support.converter.Jackson2JsonMessageConverter" />

    <!-- ============================================direct路由模式============================================ -->

    <!--定义消息队列,durable:是否持久化,如果想在RabbitMQ退出或崩溃的时候,不会失去所有的queue和消息,需要同时标志队列(queue)和交换机(exchange)是持久化的,即rabbit:queue标签和rabbit:direct-exchange中的durable=true,而消息(message)默认是持久化的可以看类org.springframework.amqp.core.MessageProperties中的属性public static final MessageDeliveryMode DEFAULT_DELIVERY_MODE = MessageDeliveryMode.PERSISTENT;exclusive: 仅创建者可以使用的私有队列,断开后自动删除;auto_delete: 当所有消费客户端连接断开后,是否自动删除队列 -->
    <rabbit:queue name="direct.queue.1" id="direct.queue.1" durable="true" auto-delete="false" exclusive="false" />
    <rabbit:queue name="direct.queue.2" id="direct.queue.2" durable="true" auto-delete="false" exclusive="false" />

    <!--绑定队列,rabbitmq的exchangeType常用的三种模式:direct,fanout,topic三种,我们用direct模式,即rabbit:direct-exchange标签,Direct交换器很简单,如果是Direct类型,就会将消息中的RoutingKey与该Exchange关联的所有Binding中的BindingKey进行比较,如果相等,则发送到该Binding对应的Queue中。有一个需要注意的地方:如果找不到指定的exchange,就会报错。但routing key找不到的话,不会报错,这条消息会直接丢失,所以此处要小心,auto-delete:自动删除,如果为Yes,则该交换机所有队列queue删除后,自动删除交换机,默认为false -->
    <rabbit:direct-exchange id="direct.exchange" name="direct.exchange" durable="true" auto-delete="false">
        <rabbit:bindings>
            <rabbit:binding queue="direct.queue.1" key="${routing.1}"></rabbit:binding>
            <rabbit:binding queue="direct.queue.2" key="${routing.2}"></rabbit:binding>
        </rabbit:bindings>
    </rabbit:direct-exchange>

    <rabbit:template exchange="direct.exchange" id="rabbitTemplate" connection-factory="connectionFactory" message-converter="jsonMessageConverter" />

    <!-- 消费者部分 -->
    <!-- 自定义接口类 -->
    <bean id="directConsumerAuto" class="com.wode.direct.DirectConsumerAuto"></bean>
    <bean id="directConsumerManual" class="com.wode.direct.DirectConsumerManual"></bean>

    <!-- 配置监听acknowledeg="manual"设置手动应答,它能够保证即使在一个worker处理消息的时候用CTRL+C来杀掉这个worker,或者一个consumer挂了(channel关闭了、connection关闭了或者TCP连接断了),也不会丢失消息。因为RabbitMQ知道没发送ack确认消息导致这个消息没有被完全处理,将会对这条消息做re-queue处理。如果此时有另一个consumer连接,消息会被重新发送至另一个consumer会一直重发,直到消息处理成功,监听容器acknowledge="auto" concurrency="30"设置发送次数,最多发送30次 -->
    <rabbit:listener-container connection-factory="connectionFactory" acknowledge="auto" concurrency="20">
        <rabbit:listener queues="direct.queue.1" ref="directConsumerAuto" />
    </rabbit:listener-container>
    <rabbit:listener-container connection-factory="connectionFactory" acknowledge="manual" concurrency="20">
        <rabbit:listener queues="direct.queue.2" ref="directConsumerManual" />
    </rabbit:listener-container>


    <!-- ============================================fanout订阅推送模式============================================ -->

    <!--定义消息队列-->
    <rabbit:queue name="fanout.queue.1" id="fanout.queue.1" durable="true" auto-delete="false" exclusive="false" />
    <rabbit:queue name="fanout.queue.2" id="fanout.queue.2" durable="true" auto-delete="false" exclusive="false" />

    <!-- Fanout 扇出,顾名思义,就是像风扇吹面粉一样,吹得到处都是。如果使用fanout类型的exchange,那么routing key就不重要了。因为凡是绑定到这个exchange的queue,都会受到消息。 -->
    <rabbit:fanout-exchange id="fanout.exchange" name="fanout.exchange" durable="true" auto-delete="false">
        <rabbit:bindings>
            <rabbit:binding queue="fanout.queue.1"></rabbit:binding>
            <rabbit:binding queue="fanout.queue.2"></rabbit:binding>
        </rabbit:bindings>
    </rabbit:fanout-exchange>

    <rabbit:template exchange="fanout.exchange" id="fanoutRabbitTemplate" connection-factory="connectionFactory" message-converter="jsonMessageConverter" />

    <!-- 消费者部分 -->
    <!-- 自定义接口类 -->
    <bean id="fanoutConsumerAuto" class="com.wode.fanout.FanoutConsumerAuto"></bean>
    <bean id="fanoutConsumerManual" class="com.wode.fanout.FanoutConsumerManual"></bean>

    <!-- 配置监听acknowledeg="manual"设置手动应答,它能够保证即使在一个worker处理消息的时候用CTRL+C来杀掉这个worker,或者一个consumer挂了(channel关闭了、connection关闭了或者TCP连接断了),也不会丢失消息。因为RabbitMQ知道没发送ack确认消息导致这个消息没有被完全处理,将会对这条消息做re-queue处理。如果此时有另一个consumer连接,消息会被重新发送至另一个consumer会一直重发,直到消息处理成功,监听容器acknowledge="auto" concurrency="30"设置发送次数,最多发送30次 -->
    <rabbit:listener-container connection-factory="connectionFactory" acknowledge="auto" concurrency="20">
        <rabbit:listener queues="fanout.queue.1" ref="fanoutConsumerAuto" />
    </rabbit:listener-container>
    <rabbit:listener-container connection-factory="connectionFactory" acknowledge="manual" concurrency="20">
        <rabbit:listener queues="fanout.queue.2" ref="fanoutConsumerManual" />
    </rabbit:listener-container>


    <!-- ============================================topic模式============================================ -->

    <!--定义消息队列-->
    <rabbit:queue name="topic.queue.1" id="topic.queue.1" durable="true" auto-delete="false" exclusive="false" />
    <rabbit:queue name="topic.queue.2" id="topic.queue.2" durable="true" auto-delete="false" exclusive="false" />

    <!-- 发送端不是按固定的routing key发送消息,而是按字符串“匹配”发送,接收端同样如此 -->
    <rabbit:topic-exchange id="topic.exchange" name="topic.exchange" durable="true" auto-delete="false">
        <rabbit:bindings>
            <rabbit:binding queue="topic.queue.1" pattern="order.*" />
            <rabbit:binding queue="topic.queue.2" pattern="*.insert" />
        </rabbit:bindings>
    </rabbit:topic-exchange>

    <rabbit:template exchange="topic.exchange" id="topicRabbitTemplate" connection-factory="connectionFactory" message-converter="jsonMessageConverter" />

    <!-- 消费者部分 -->
    <!-- 自定义接口类 -->
    <bean id="topicConsumerAuto" class="com.wode.topic.TopicConsumerAuto"></bean>
    <bean id="topicConsumerManual" class="com.wode.topic.TopicConsumerManual"></bean>

    <!-- 配置监听acknowledeg="manual"设置手动应答,它能够保证即使在一个worker处理消息的时候用CTRL+C来杀掉这个worker,或者一个consumer挂了(channel关闭了、connection关闭了或者TCP连接断了),也不会丢失消息。因为RabbitMQ知道没发送ack确认消息导致这个消息没有被完全处理,将会对这条消息做re-queue处理。如果此时有另一个consumer连接,消息会被重新发送至另一个consumer会一直重发,直到消息处理成功,监听容器acknowledge="auto" concurrency="30"设置发送次数,最多发送30次 -->
    <rabbit:listener-container connection-factory="connectionFactory" acknowledge="auto" concurrency="20">
        <rabbit:listener queues="topic.queue.1" ref="topicConsumerAuto" />
    </rabbit:listener-container>
    <rabbit:listener-container connection-factory="connectionFactory" acknowledge="manual" concurrency="20">
        <rabbit:listener queues="topic.queue.2" ref="topicConsumerManual" />
    </rabbit:listener-container>


</beans>

  c.创建 rabbit.properties

#RabbitMQ服务器地址,默认值"localhost"
rabbit.ip=localhost
#RabbitMQ服务端口,默认值为5672
rabbit.port=5672
#访问RabbitMQ服务器的账户,默认是guest
rabbit.username=guest
#访问RabbitMQ服务器的密码,默认是guest
rabbit.password=guest

#路由标识
routing.1=1
routing.2=2

3.创建生产者

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component
public class CommonProducer {

    //direct模式
    @Resource(name = "rabbitTemplate")
    private AmqpTemplate rabbitTemplate;

    @Value("${routing.1}")
    private String routing1;
    @Value("${routing.2}")
    private String routing2;

    //fanout模式
    @Resource(name = "fanoutRabbitTemplate")
    private AmqpTemplate fanoutRabbitTemplate;

    //topic模式
    @Resource(name = "topicRabbitTemplate")
    private AmqpTemplate topicRabbitTemplate;


    public void send(){
        rabbitTemplate.convertAndSend(routing1, "routing1");
        rabbitTemplate.convertAndSend(routing2, "routing2");

        fanoutRabbitTemplate.convertAndSend("fanoutMsg");

        topicRabbitTemplate.convertAndSend("order.insert", "order.insert");
        topicRabbitTemplate.convertAndSend("order.update", "order.update");
    }

}

4.创建direct模式消费者

  a.自动提交消费者,对应配置文件中 acknowledge="auto"

import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;

public class DirectConsumerAuto implements ChannelAwareMessageListener {
    @Override
    public void onMessage(Message message, Channel channel) throws Exception {
        String msg = new String(message.getBody(),"UTF-8");
        System.out.println("[DirectConsumerAuto]消费者接收到:" + msg);
    }
}

  b.手动提交消费者,对应配置文件中 acknowledge="manual"

import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;

public class DirectConsumerManual implements ChannelAwareMessageListener {
    @Override
    public void onMessage(Message message, Channel channel) throws Exception {
        String msg = new String(message.getBody(),"UTF-8");
        System.out.println("[DirectConsumerManual]消费者接收到:" + msg);
        //手动确认
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
    }
}

5.创建fanout模式消费者

  a.自动提交消费者,对应配置文件中 acknowledge="auto"

import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;

public class FanoutConsumerAuto implements ChannelAwareMessageListener {
    @Override
    public void onMessage(Message message, Channel channel) throws Exception {
        String msg = new String(message.getBody(),"UTF-8");
        System.out.println("[FanoutConsumerAuto]消费者接收到:" + msg);
    }
}

  b.手动提交消费者,对应配置文件中 acknowledge="manual"

import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;

public class FanoutConsumerManual implements ChannelAwareMessageListener {
    @Override
    public void onMessage(Message message, Channel channel) throws Exception {
        String msg = new String(message.getBody(),"UTF-8");
        System.out.println("[FanoutConsumerManual]消费者接收到:" + msg);
        //手动确认
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
    }
}

6.创建topic模式消费者

  a.自动提交消费者,对应配置文件中 acknowledge="auto"

import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;

public class TopicConsumerAuto implements ChannelAwareMessageListener {
    @Override
    public void onMessage(Message message, Channel channel) throws Exception {
        String msg = new String(message.getBody(),"UTF-8");
        System.out.println("[TopicConsumerAuto]消费者接收到:" + msg);
    }
}

  b.手动提交消费者,对应配置文件中 acknowledge="manual"

import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;

public class TopicConsumerManual implements ChannelAwareMessageListener {
    @Override
    public void onMessage(Message message, Channel channel) throws Exception {
        String msg = new String(message.getBody(),"UTF-8");
        System.out.println("[TopicConsumerManual]消费者接收到:" + msg);
        //手动确认
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
    }
}

7.测试

public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        CommonProducer commonProducer = (CommonProducer) applicationContext.getBean("commonProducer");
        commonProducer.send();
    }
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
Java获得今日零时零分零秒的时间(Date型)
publicDatezeroTime()throwsParseException{    DatetimenewDate();    SimpleDateFormatsimpnewSimpleDateFormat("yyyyMMdd00:00:00");    SimpleDateFormatsimp2newS
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这