SpringBoot整合RabbitMq(二)
本文序列化和添加package参考:https://www.jianshu.com/p/13fd9ff0648d
RabbitMq安装
[root@topcheer ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
elasticsearch latest 874179f19603 11 days ago 771 MB
springbootdemo4docker latest cd13bc7f56a0 2 weeks ago 678 MB
docker.io/tomcat latest ee48881b3e82 4 weeks ago 506 MB
docker.io/rabbitmq latest a00bc560660a 4 weeks ago 147 MB
docker.io/centos latest 67fa590cfc1c 7 weeks ago 202 MB
docker.io/redis latest f7302e4ab3a8 8 weeks ago 98.2 MB
docker.io/rabbitmq 3.7.16-management 3f92e6354d11 2 months ago 177 MB
[root@topcheer ~]# docker run -d -p 5672:5672 -p 15672:15672 --name myrabbitmq 3f92e6354d11
ab8a0c8bae576f12ff334b22aae36d5fd87e744062462765628b06b5a65b9005
[root@topcheer ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ab8a0c8bae57 3f92e6354d11 "docker-entrypoint..." 27 seconds ago Up 26 seconds 4369/tcp, 5671/tcp, 0.0.0.0:5672->5672/tcp, 15671/tcp, 25672/tcp, 0.0.0.0:15672->15672/tcp myrabbitmq
[root@topcheer ~]#
账号密码都为guest,创建交换机
进行交换机和队列进行绑定
Springboot开发
<dependencies>
<!--消息队列依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!--web相关依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--fastjson依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.44</version>
</dependency>
<!--lombok依赖-->
<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>
启动类
/**
* 自动配置
* 1、RabbitAutoConfiguration
* 2、有自动配置了连接工厂ConnectionFactory;
* 3、RabbitProperties 封装了 RabbitMQ的配置
* 4、 RabbitTemplate :给RabbitMQ发送和接受消息;
* 5、 AmqpAdmin : RabbitMQ系统管理功能组件;
* AmqpAdmin:创建和删除 Queue,Exchange,Binding
* 6、@EnableRabbit + @RabbitListener 监听消息队列的内容
*
*/
@MapperScan("com.topcheer.*.*.dao")
@SpringBootApplication
@EnableCaching
@EnableRabbit
public class Oss6Application {
public static void main(String[] args) {
SpringApplication.run(Oss6Application.class, args);
}
}
配置文件
spring:
rabbitmq:
host: 192.168.180.113
username: guest
password: guest
Bo类
/**
* @author WGR
* @create 2019/9/3 -- 0:34
*/
@Document(indexName = "topcheer",type = "book" )
@Slf4j
@Data
//@Builder 用这个来构造,反序列化的时候会出问题
public class Book implements Serializable {
private Integer id;
private String name;
private String author; public Book(String name, String author) {
this.name = name;
this.author = author;
}
public Book(Integer id, String name, String author) {
this.id = id;
this.name = name;
this.author = author;
}
public Book() {
}
}
MessageConverter
我们先来创建一个转换的实现类,只需要继承抽象类AbstractMessageConverter
并实现内部的createMessage
、fromMessage
两个方法就可以完成实体类的序列化
与反序列化
的转换,代码如下所示:
/**
* 自定义消息转换器
* 采用FastJson完成消息转换
*
* @author:于起宇 <br/>
* ===============================
* Created with Eclipse.
* Date:2017/10/26
* Time:19:28
* 简书:http://www.jianshu.com/u/092df3f77bca
* ================================
*/
public class RabbitMqFastJsonConverter
extends AbstractMessageConverter {
/**
* 日志对象实例
*/
private Logger logger = LoggerFactory.getLogger(RabbitMqFastJsonConverter.class);
/**
* 消息类型映射对象
*/
private static ClassMapper classMapper = new DefaultClassMapper();
/**
* 默认字符集
*/
private static String DEFAULT_CHART_SET = "UTF-8";
/**
* 创建消息
*
* @param o 消息对象
* @param messageProperties 消息属性
* @return
*/
@Override
protected Message createMessage(Object o, MessageProperties messageProperties) {
byte[] bytes = null;
try {
String jsonString = JSON.toJSONString(o);
bytes = jsonString.getBytes(DEFAULT_CHART_SET);
} catch (IOException e) {
throw new MessageConversionException(
"Failed to convert Message content", e);
}
messageProperties.setContentType(MessageProperties.CONTENT_TYPE_JSON);
messageProperties.setContentEncoding(DEFAULT_CHART_SET);
if (bytes != null) {
messageProperties.setContentLength(bytes.length);
}
classMapper.fromClass(o.getClass(), messageProperties);
return new Message(bytes, messageProperties);
}
/**
* 转换消息为对象
*
* @param message 消息对象
* @return
* @throws MessageConversionException
*/
@Override
public Object fromMessage(Message message) throws MessageConversionException {
Object content = null;
MessageProperties properties = message.getMessageProperties();
if (properties != null) {
String contentType = properties.getContentType();
if (contentType != null && contentType.contains("json")) {
String encoding = properties.getContentEncoding();
if (encoding == null) {
encoding = DEFAULT_CHART_SET;
}
try {
Class<?> targetClass = classMapper.toClass(
message.getMessageProperties());
content = convertBytesToObject(message.getBody(),
encoding, targetClass);
} catch (IOException e) {
throw new MessageConversionException(
"Failed to convert Message content", e);
}
} else {
logger.warn("Could not convert incoming message with content-type ["
+ contentType + "]");
}
}
if (content == null) {
content = message.getBody();
}
return content;
}
/**
* 将字节数组转换成实例对象
*
* @param body Message对象主体字节数组
* @param encoding 字符集
* @param clazz 类型
* @return
* @throws UnsupportedEncodingException
*/
private Object convertBytesToObject(byte[] body, String encoding,
Class<?> clazz) throws UnsupportedEncodingException {
String contentAsString = new String(body, encoding);
return JSON.parseObject(contentAsString, clazz);
}
}
在该转换类内我们使用了DefaultClassMapper来作为类的映射,我们可以先来看下该类相关信任package的源码,如下所示: ......
public class DefaultClassMapper implements ClassMapper, InitializingBean {
public static final String DEFAULT_CLASSID_FIELD_NAME = "__TypeId__";
private static final String DEFAULT_HASHTABLE_TYPE_ID = "Hashtable";
// 默认信任的package列表
private static final List<String> TRUSTED_PACKAGES = Arrays.asList("java.util", "java.lang");
private final Set<String> trustedPackages;
private volatile Map<String, Class<?>> idClassMapping;
private volatile Map<Class<?>, String> classIdMapping;
private volatile Class<?> defaultMapClass;
private volatile Class<?> defaultType;
public DefaultClassMapper() {
// 构造函数初始化信任的package为默认的pakcage列表
// 仅支持java.util、java.lang两个package
this.trustedPackages = new LinkedHashSet(TRUSTED_PACKAGES);
this.idClassMapping = new HashMap();
this.classIdMapping = new HashMap();
this.defaultMapClass = LinkedHashMap.class;
this.defaultType = LinkedHashMap.class;
}
......
RabbitMqConfiguration
下面我们需要将该转换设置到RabbitTemplate
、SimpleRabbitListenerContainerFactory
内,让RabbitMQ
支持自定义的消息转换,如下所示:
/**
* rabbitmq 相关配置
* @author:于起宇 <br/>
* ===============================
* Created with IDEA.
* Date:2018/3/11
* Time:下午5:42
* 简书:http://www.jianshu.com/u/092df3f77bca
* ================================
*/
@Configuration
public class RabbitMqConfiguration {
/**
* 配置消息队列模版
* 并且设置MessageConverter为自定义FastJson转换器
* @param connectionFactory
* @return
*/
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate template = new RabbitTemplate(connectionFactory);
template.setMessageConverter(new RabbitMqFastJsonConverter());
return template;
}
/**
* 自定义队列容器工厂
* 并且设置MessageConverter为自定义FastJson转换器
* @param connectionFactory
* @return
*/
@Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setMessageConverter(new RabbitMqFastJsonConverter());
factory.setDefaultRequeueRejected(false);
return factory;
}
}
重写DefaultClassMapper构造函数
不加这个会报错,显示这个类没有被信任
创建一个名为RabbitMqFastJsonClassMapper
的类并且继承DefaultClassMapper
,如下所示:
/**
* fastjson 转换映射
*
* @author:于起宇 <br/>
* ===============================
* Created with IDEA.
* Date:2018/3/13
* Time:下午10:17
* 简书:http://www.jianshu.com/u/092df3f77bca
* ================================
*/
public class RabbitMqFastJsonClassMapper extends DefaultClassMapper {
/**
* 构造函数初始化信任所有pakcage
*/
public RabbitMqFastJsonClassMapper() {
super();
setTrustedPackages("*");
}
}
在上面构造函数内我们设置了信任全部的package
,添加了RabbitMqFastJsonClassMapper
类后,需要让MessageConverter
使用该类作为映射,修改RabbitMqFastJsonConverter
部分代码如下所示:
/**
* 消息类型映射对象
*/
private static ClassMapper classMapper = new DefaultClassMapper();
>>> 修改为 >>>
/**
* 消息类型映射对象
*/
private static ClassMapper classMapper = new RabbitMqFastJsonClassMapper();
监听类
@Service
public class BookService {
@RabbitListener(queues = "topcheer.news")
public void receive(Book book){
System.out.println("收到消息:"+book);
}
@RabbitListener(queues = "topcheer")
public void receive02(Message message){
System.out.println(message.getBody());
System.out.println(message.getMessageProperties());
}
}
测试类
/**
* 1、单播(点对点)
*/
@Test
public void contextLoads() {
//Message需要自己构造一个;定义消息体内容和消息头
//rabbitTemplate.send(exchage,routeKey,message);
//object默认当成消息体,只需要传入要发送的对象,自动序列化发送给rabbitmq;
//rabbitTemplate.convertAndSend(exchage,routeKey,object);
Map<String,Object> map = new HashMap<>();
map.put("msg","这是第一个消息");
map.put("data", Arrays.asList("helloworld",123,true));
//对象被默认序列化以后发送出去
rabbitTemplate.convertAndSend("exchange-direct","topcheer",new Book("红楼梦","曹雪芹"));
}
//接受数据,如何将数据自动的转为json发送出去
@Test
public void receive(){
Object o = rabbitTemplate.receiveAndConvert("topcheer.news");
// System.out.println(o.getClass());
System.out.println(o);
}
/**
* 广播
*/
@Test
public void sendMsg(){
rabbitTemplate.convertAndSend("exchange-fanout","",new Book("红楼梦1","曹雪芹1"));
}
测试结果如下:
2019-10-11 22:20:50.730 INFO --- [ main] tMqFastJsonConverter : 消息为对象
Book(id=null, name=红楼梦, author=曹雪芹)
2019-10-11 22:39:04.284 INFO --- [ntContainer#1-1] tMqFastJsonConverter : 消息为对象
[B@4da0a5ae
MessageProperties [headers={__TypeId__=com.topcheer.oss.shiro.bo.Book}, contentType=application/json, contentEncoding=UTF-8, contentLength=0, receivedDeliveryMode=PERSISTENT, priority=0, redelivered=false, receivedExchange=exchange-direct, receivedRoutingKey=topcheer, deliveryTag=4, consumerTag=amq.ctag-mFGYgGzoHK3Utt8uk2Hxdg, consumerQueue=topcheer]
SpringBoot整合RabbitMq(二)的更多相关文章
- springboot学习笔记-6 springboot整合RabbitMQ
一 RabbitMQ的介绍 RabbitMQ是消息中间件的一种,消息中间件即分布式系统中完成消息的发送和接收的基础软件.这些软件有很多,包括ActiveMQ(apache公司的),RocketMQ(阿 ...
- 一篇学习完rabbitmq基础知识,springboot整合rabbitmq
一 rabbitmq 介绍 MQ全称为Message Queue,即消息队列, RabbitMQ是由erlang语言开发,基于AMQP(Advanced MessageQueue 高级消息队列协议 ...
- 功能:SpringBoot整合rabbitmq,长篇幅超详细
SpringBoot整合rabbitMq 一.介绍 消息队列(Message Queue)简称mq,本文将介绍SpringBoot整合rabbitmq的功能使用 队列是一种数据结构,就像排队一样,遵循 ...
- RabbitMQ入门到进阶(Spring整合RabbitMQ&SpringBoot整合RabbitMQ)
1.MQ简介 MQ 全称为 Message Queue,是在消息的传输过程中保存消息的容器.多用于分布式系统 之间进行通信. 2.为什么要用 MQ 1.流量消峰 没使用MQ 使用了MQ 2.应用解耦 ...
- 【SpringBoot系列5】SpringBoot整合RabbitMQ
前言: 因为项目需要用到RabbitMQ,前几天就看了看RabbitMQ的知识,记录下SpringBoot整合RabbitMQ的过程. 给出两个网址: RabbitMQ官方教程:http://www. ...
- SpringBoot系列八:SpringBoot整合消息服务(SpringBoot 整合 ActiveMQ、SpringBoot 整合 RabbitMQ、SpringBoot 整合 Kafka)
声明:本文来源于MLDN培训视频的课堂笔记,写在这里只是为了方便查阅. 1.概念:SpringBoot 整合消息服务 2.具体内容 对于异步消息组件在实际的应用之中会有两类: · JMS:代表作就是 ...
- 【MQ中间件】RabbitMQ -- SpringBoot整合RabbitMQ(3)
1.前言说明 前面一篇博客中提到了使用原生java代码进行测试RabbitMQ实现多种交换机类型的队列场景.但是在项目中我们一般使用SpringBoot项目,而且RabbitMQ天生对于Spring的 ...
- springboot整合rabbitmq实现生产者消息确认、死信交换器、未路由到队列的消息
在上篇文章 springboot 整合 rabbitmq 中,我们实现了springboot 和rabbitmq的简单整合,这篇文章主要是对上篇文章功能的增强,主要完成如下功能. 需求: 生产者在启 ...
- Springboot 整合RabbitMq ,用心看完这一篇就够了
该篇文章内容较多,包括有rabbitMq相关的一些简单理论介绍,provider消息推送实例,consumer消息消费实例,Direct.Topic.Fanout的使用,消息回调.手动确认等. (但是 ...
随机推荐
- 深入Dapper.NET源码 (文长)
目录 前言.目录.安装环境 Dynamic Query 原理 Part1 Dynamic Query 原理 Part2 Strongly Typed Mapping 原理 Part1 : ADO.NE ...
- phaser学习总结之Tween详解
前言 在上一章phaser学习总结之phaser入门教程中,我们已经初步入门了phaser,并通过一个案例了解了phaser,现在我们需要对phaser中的对象进行讲解,本章需要讲解的是tween,即 ...
- 快学Scala 第二十课 (trait的构造顺序)
trait的构造顺序: 首先调用超类构造器 特质构造器在超类构造器之后,类构造器之前执行 特质从左向右被构造 每个特质当中,父特质先被构造 如果多个特质共有一个父特质,而那个父特质已经被构造,则不会被 ...
- Flutter学习笔记(29)--Flutter如何与native进行通信
如需转载,请注明出处:Flutter学习笔记(29)--Flutter如何与native进行通信 前言:在我们开发Flutter项目的时候,难免会遇到需要调用native api或者是其他的情况,这时 ...
- springboot结合jpa
idea中新建springboot项目,引入spring-boot-starter-data-jpa依赖 application.yml中配置数据库连接,示例如下: spring: datasourc ...
- Formform
知识预览 一 Django的form组件 二 Django的model form组件 三 Django的缓存机制 四 Django的信号 五 Django的序列化 回到顶部 一 Django的form ...
- js中的toString和valueOf
数据的转换 基本上,所有JS数据类型都拥有valueOf和toString这两个方法,null除外.它们俩解决javascript值运算与显示的问题 所有对象继承了两个转换方法: 第一个是toStri ...
- 解决:Specifying a namespace in include() without providing an app_name和XXX is not a registered namespace问题
python3 Django 环境下,如果你遇到namespace没有注册以及在根目录下urls.py中的include方法的第二个参数namespace添加之后就出错的问题. 出错问题: 'Spec ...
- drf源码save以及response
drf源码save以及response 一.save 其中蛮重要的一段 if self.instance is not None: self.instance = self.update(self.i ...
- Ubuntu16.04换源
换成国内最快的阿里云源 第一步:备份原来的源文件 cd /etc/apt/ 然后会显示下面的源文件sources.list 输入命令 sudo cp sources.list sources.list ...