第四十八章:SpringBoot2.0新特性 - RabbitMQ信任package设置

本文主要是介绍第四十八章:SpringBoot2.0新特性 - RabbitMQ信任package设置,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在这次SpringBoot升级后,之前的系统内使用实体传输受到了限制,如果使用SpringBoot默认的序列化方式不会出现信任package的问题,之所以出现这个问题是因为项目使用fastjson方式进行类的序列化已经反序列化,在之前SpringBoot 1.5.10版本的时候 RabbitMQ依赖内的DefaultClassMapper类在构造函数内配置*,表示信任项目内的所有package,在SpringBoot 2.0.0版本时,DefaultClassMapper类源码构造函数进行了修改,不再信任全部package而是仅仅信任java.utiljava.lang

本章目标

基于SpringBoot2.0使用RabbitMQ自定义MessageConverter配置信任指定package或者全部package

SpringBoot 企业级核心技术学习专题

专题专题名称专题描述
001Spring Boot 核心技术讲解SpringBoot一些企业级层面的核心组件
002Spring Boot 核心技术章节源码Spring Boot 核心技术简书每一篇文章码云对应源码
003Spring Cloud 核心技术对Spring Cloud核心技术全面讲解
004Spring Cloud 核心技术章节源码Spring Cloud 核心技术简书每一篇文章对应源码
005QueryDSL 核心技术全面讲解QueryDSL核心技术以及基于SpringBoot整合SpringDataJPA
006SpringDataJPA 核心技术全面讲解SpringDataJPA核心技术

构建项目

创建项目添加对应依赖,pom.xml配置文件如下所示:

<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></dependencies>
消息队列配置文件

我们需要在application.properties配置文件内添加RabbitMQ相应的配置信息,如下所示:

spring.rabbitmq.host=localhost
spring.rabbitmq.username=admin
spring.rabbitmq.password=admin
spring.rabbitmq.virtual-host=/hengyu

具体消息队列的连接配置信息需要根据实际情况填写。

队列常量配置

我们之前的文章都是采用的Enum方式来配置队列相关的ExchangeNameRouteKey等相关的信息,使用枚举有个弊端,无法在注解内作为属性的值使用,所以我们之前的Consumer类配置监听的队列时都是字符串的形式,这样后期修改时还要修改多个地方(当然队列信息很少变动),我们本章使用Constants常量的形式进行配置,如下所示:

/*** 队列常量配置* @author:于起宇 <br/>* ===============================* Created with IDEA.* Date:2018/3/7* Time:下午10:10* 简书:http://www.jianshu.com/u/092df3f77bca* ================================*/
public interface QueueConstants {/*** 消息交换*/String MESSAGE_EXCHANGE = "message.direct.exchange";/*** 消息队列名称*/String MESSAGE_QUEUE_NAME = "message.queue";/*** 消息路由键*/String MESSAGE_ROUTE_KEY = "message.send";
}
示例消息队列JavaConfig配置

本章是为了设置信任package,所以这里使用消息中心队列来模拟,配置代码如下所示:

/*** 消息队列配置类** @author:于起宇 <br/>* ===============================* Created with IDEA.* Date:2018/3/7* Time:下午10:07* 简书:http://www.jianshu.com/u/092df3f77bca* ================================*/
@Configuration
public class MessageRabbitMqConfiguration {/*** 交换配置** @return*/@Beanpublic DirectExchange messageDirectExchange() {return (DirectExchange) ExchangeBuilder.directExchange(QueueConstants.MESSAGE_EXCHANGE).durable(true).build();}/*** 消息队列声明** @return*/@Beanpublic Queue messageQueue() {return QueueBuilder.durable(QueueConstants.MESSAGE_QUEUE_NAME).build();}/*** 消息绑定** @return*/@Beanpublic Binding messageBinding() {return BindingBuilder.bind(messageQueue()).to(messageDirectExchange()).with(QueueConstants.MESSAGE_ROUTE_KEY);}
}

上面配置类内添加ExchangeQueueBinding等配置,将messageQueue使用message.send路由键与messageDirectExchange交换配置进行绑定。

我们在之前说了只有传递实体类时才会出现信任package问题,下面我们需要创建一个简单的消息传输实体,如下所示:

/*** 消息实体** @author:于起宇 <br/>* ===============================* Created with IDEA.* Date:2018/3/11* Time:下午5:18* 简书:http://www.jianshu.com/u/092df3f77bca* ================================*/
@Data
public class MessageEntity implements Serializable {/*** 消息内容*/private String content;
}

该实体类仅添加了一个content字段,这样足够模拟我们的场景了,到这里我们的配置已经处理完,下面就是我们的队列的Provider以及Consumer的相关实体类编写。

消息提供者

为队列message.queue添加Provider的代码实现,如下所示:

/*** 消息队列 - 消息提供者* @author:于起宇 <br/>* ===============================* Created with IDEA.* Date:2018/3/11* Time:下午6:16* 简书:http://www.jianshu.com/u/092df3f77bca* ================================*/
@Component
public class MessageProvider {/*** logger instance*/static Logger logger = LoggerFactory.getLogger(MessageProvider.class);/*** 消息队列模板*/@Autowiredprivate AmqpTemplate amqpTemplate;public void sendMessage(Object object) {logger.info("写入消息队列内容:{}", JSON.toJSONString(object));amqpTemplate.convertAndSend(QueueConstants.MESSAGE_EXCHANGE, QueueConstants.MESSAGE_ROUTE_KEY, object);}
}
消息消费者

当然我们有了Provider必然要有对应的Consumer,消费者代码实现如下所示:

/*** 消息队列 - 消息消费者* @author:于起宇 <br/>* ===============================* Created with IDEA.* Date:2018/3/11* Time:下午5:32* 简书:http://www.jianshu.com/u/092df3f77bca* ================================*/
@Component
@RabbitListener(queues = QueueConstants.MESSAGE_QUEUE_NAME)
public class MessageConsumer {/*** logger instance*/static Logger logger = LoggerFactory.getLogger(MessageConsumer.class);@RabbitHandlerpublic void handler(@Payload MessageEntity messageEntity) {logger.info("消费内容:{}", JSON.toJSONString(messageEntity));}
}
创建测试控制器

我们采用控制器发送Get请求的方式进行发送消息,创建名为TestController的控制器,并添加测试方法,如下代码所示:

/*** 测试控制器* @author:于起宇 <br/>* ===============================* Created with IDEA.* Date:2018/3/11* Time:下午5:43* 简书:http://www.jianshu.com/u/092df3f77bca* ================================*/
@RestController
public class TestController {/*** 消息队列 - 消息提供者 注入*/@Autowiredprivate MessageProvider messageProvider;/*** 测试发送消息队列方法** @param messageEntity 发送消息实体内容* @return*/@RequestMapping(value = "/index")public String index(MessageEntity messageEntity) {// 将实体实例写入消息队列messageProvider.sendMessage(messageEntity);return "Success";}
}
测试RabbitMQ默认实体传输

下面我们启动项目,首先先来测试RabbitMQ默认的实体类方式,当然这种默认的方式不会产生信任package的情况。

我们为了证实这一点,来访问(http://localhost:8080/index?content=admin)[http://localhost:8080/index?content=admin],我们传递content的值为admin,访问效果控制台输出内容如下:

2018-03-13 21:59:08.844  INFO 16047 --- [nio-8080-exec-1] c.h.chapter48.provider.MessageProvider   : 写入消息队列内容:{"content":"admin"}
2018-03-13 21:59:08.898  INFO 16047 --- [cTaskExecutor-1] c.h.chapter48.consumer.MessageConsumer   : 消费内容:{"content":"admin"}

可以看到控制台的输出内容,直接完成了消息的消费,是没有任何问题的,下面我们对RabbitMQ添加自定义MessageConverter的配置,使用fastjson替代默认转换方式。

MessageConverter

我们先来创建一个转换的实现类,只需要继承抽象类AbstractMessageConverter并实现内部的createMessagefromMessage两个方法就可以完成实体类的序列化反序列化的转换,代码如下所示:

/*** 自定义消息转换器* 采用FastJson完成消息转换** @author:于起宇 <br/>* ===============================* Created with Eclipse.* Date:2017/10/26* Time:19:28* 简书:http://www.jianshu.com/u/092df3f77bca* ================================*/
public class RabbitMqFastJsonConverterextends 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*/@Overrideprotected 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*/@Overridepublic 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两个packagethis.trustedPackages = new LinkedHashSet(TRUSTED_PACKAGES);this.idClassMapping = new HashMap();this.classIdMapping = new HashMap();this.defaultMapClass = LinkedHashMap.class;this.defaultType = LinkedHashMap.class;}
......
RabbitMqConfiguration

下面我们需要将该转换设置到RabbitTemplateSimpleRabbitListenerContainerFactory内,让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*/@Beanpublic RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {RabbitTemplate template = new RabbitTemplate(connectionFactory);template.setMessageConverter(new RabbitMqFastJsonConverter());return template;}/*** 自定义队列容器工厂* 并且设置MessageConverter为自定义FastJson转换器* @param connectionFactory* @return*/@Beanpublic SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();factory.setConnectionFactory(connectionFactory);factory.setMessageConverter(new RabbitMqFastJsonConverter());factory.setDefaultRequeueRejected(false);return factory;}}
重启测试

上面的代码配置我们已经把MessageConverter改成了fastjson,重启项目,再次访问http://localhost:8080/index?content=admin路径,看下控制台输出日志内容如下所示:

Caused by: java.lang.IllegalArgumentException: The class 'com.hengyu.chapter48.entity.MessageEntity' is not in the trusted packages: [java.util, java.lang]. If you believe this class is safe to deserialize, please provide its name. If the serialization is only done by a trusted source, you can also enable trust all (*).at org.springframework.amqp.support.converter.DefaultClassMapper.toClass(DefaultClassMapper.java:211) ~[spring-amqp-2.0.2.RELEASE.jar:2.0.2.RELEASE]at org.springframework.amqp.support.converter.DefaultClassMapper.toClass(DefaultClassMapper.java:199) ~[spring-amqp-2.0.2.RELEASE.jar:2.0.2.RELEASE]at com.hengyu.chapter48.RabbitMqFastJsonConverter.fromMessage(RabbitMqFastJsonConverter.java:88) ~[classes/:na]at org.springframework.amqp.rabbit.listener.adapter.AbstractAdaptableMessageListener.extractMessage(AbstractAdaptableMessageListener.java:246) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter$MessagingMessageConverterAdapter.extractPayload(MessagingMessageListenerAdapter.java:266) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]at org.springframework.amqp.support.converter.MessagingMessageConverter.fromMessage(MessagingMessageConverter.java:118) ~[spring-amqp-2.0.2.RELEASE.jar:2.0.2.RELEASE]at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.toMessagingMessage(MessagingMessageListenerAdapter.java:168) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.onMessage(MessagingMessageListenerAdapter.java:115) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1414) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]... 8 common frames omitted

可以看到控制台已经输出了不信任com.hengyu.chapter48.entity.MessageEntity实体的错误信息,也表明了仅信任java.utiljava.lang两个package,下面我们就需要继承DefaultClassMapper来重写构造函数完成信任指定的package

重写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();
再次重启测试

我们再次重启项目后,仍然访问http://localhost:8080/index?content=admin路径,查看控制台日志如下所示:

2018-03-13 22:23:35.414  INFO 16121 --- [nio-8080-exec-1] c.h.chapter48.provider.MessageProvider   : 写入消息队列内容:{"content":"admin"}
2018-03-13 22:23:35.493  INFO 16121 --- [cTaskExecutor-1] c.h.chapter48.consumer.MessageConsumer   : 消费内容:{"content":"admin"}

根据日志输出已经证明可以正常的完成消息的消费。

总结

如果使用RabbitMQ默认的转换方式,并不会涉及到本章遇到的信任package问题,如果想自定义消息转换并且使用DefaultClassMapper作为映射,肯定会出现信任package的问题,所以如果需要自定义转换的小伙伴,记住要设置trustedPackages

本章源码已经上传到码云:
SpringBoot配套源码地址:https://gitee.com/hengboy/spring-boot-chapter
SpringCloud配套源码地址:https://gitee.com/hengboy/spring-cloud-chapter
SpringBoot相关系列文章请访问:目录:SpringBoot学习目录
QueryDSL相关系列文章请访问:QueryDSL通用查询框架学习目录
SpringDataJPA相关系列文章请访问:目录:SpringDataJPA学习目录,感谢阅读!
欢迎加入QQ技术交流群,共同进步。
QQ技术交流群

这篇关于第四十八章:SpringBoot2.0新特性 - RabbitMQ信任package设置的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:https://blog.csdn.net/weixin_42033269/article/details/80048042
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/503273

相关文章

C#特性(Attributes)和反射(Reflection)详解

《C#特性(Attributes)和反射(Reflection)详解》:本文主要介绍C#特性(Attributes)和反射(Reflection),具有很好的参考价值,希望对大家有所帮助,如有错误... 目录特性特性的定义概念目的反射定义概念目的反射的主要功能包括使用反射的基本步骤特性和反射的关系总结特性

PyTorch高级特性与性能优化方式

《PyTorch高级特性与性能优化方式》:本文主要介绍PyTorch高级特性与性能优化方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、自动化机制1.自动微分机制2.动态计算图二、性能优化1.内存管理2.GPU加速3.多GPU训练三、分布式训练1.分布式数据

CentOS和Ubuntu系统使用shell脚本创建用户和设置密码

《CentOS和Ubuntu系统使用shell脚本创建用户和设置密码》在Linux系统中,你可以使用useradd命令来创建新用户,使用echo和chpasswd命令来设置密码,本文写了一个shell... 在linux系统中,你可以使用useradd命令来创建新用户,使用echo和chpasswd命令来设

SpringBoot3.4配置校验新特性的用法详解

《SpringBoot3.4配置校验新特性的用法详解》SpringBoot3.4对配置校验支持进行了全面升级,这篇文章为大家详细介绍了一下它们的具体使用,文中的示例代码讲解详细,感兴趣的小伙伴可以参考... 目录基本用法示例定义配置类配置 application.yml注入使用嵌套对象与集合元素深度校验开发

C#TextBox设置提示文本方式(SetHintText)

《C#TextBox设置提示文本方式(SetHintText)》:本文主要介绍C#TextBox设置提示文本方式(SetHintText),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑... 目录C#TextBox设置提示文本效果展示核心代码总结C#TextBox设置提示文本效果展示核心代

Pyserial设置缓冲区大小失败的问题解决

《Pyserial设置缓冲区大小失败的问题解决》本文主要介绍了Pyserial设置缓冲区大小失败的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录问题描述原因分析解决方案问题描述使用set_buffer_size()设置缓冲区大小后,buf

Feign Client超时时间设置不生效的解决方法

《FeignClient超时时间设置不生效的解决方法》这篇文章主要为大家详细介绍了FeignClient超时时间设置不生效的原因与解决方法,具有一定的的参考价值,希望对大家有一定的帮助... 在使用Feign Client时,可以通过两种方式来设置超时时间:1.针对整个Feign Client设置超时时间

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整

新特性抢先看! Ubuntu 25.04 Beta 发布:Linux 6.14 内核

《新特性抢先看!Ubuntu25.04Beta发布:Linux6.14内核》Canonical公司近日发布了Ubuntu25.04Beta版,这一版本被赋予了一个活泼的代号——“Plu... Canonical 昨日(3 月 27 日)放出了 Beta 版 Ubuntu 25.04 系统镜像,代号“Pluc

PyCharm如何设置新建文件默认为LF换行符

《PyCharm如何设置新建文件默认为LF换行符》:本文主要介绍PyCharm如何设置新建文件默认为LF换行符问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录PyCharm设置新建文件默认为LF换行符设置换行符修改换行符总结PyCharm设置新建文件默认为LF