RabbitMQ在Spring中的应用
相关依赖的安装
在安装相关依赖的时候要特别注意amqp-client
的版本和spring-boot
的版本,amqp-client
版本过低可能会出现错误
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.6.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
SpringAMQP用户管理组件-RabbitAdmin
- Spring中加载RabbitMQ配置信息
@Configuration
@ComponentScan({"com.rabbitmq.spring.*"})
public class RabbitMQConfiguration {
@Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setAddresses("localhost:5672");
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
connectionFactory.setVirtualHost("/");
return connectionFactory;
}
@Bean
public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
rabbitAdmin.setAutoStartup(true);
return rabbitAdmin;
}
}
- 进行测试,验证是否加载成功
@SpringBootTest
class RabbitSpringApplicationTests {
@Test
void contextLoads() {
}
@Autowired
private RabbitAdmin rabbitAdmin;
@Test
public void testAdmin() {
// 声明交换机
rabbitAdmin.declareExchange(new DirectExchange("test.direct", false, false));
rabbitAdmin.declareExchange(new FanoutExchange("test.fanout", false, false));
// 声明队列
rabbitAdmin.declareQueue(new Queue("test.direct.queue", false));
// 声明绑定
rabbitAdmin.declareBinding(new Binding("test.direct.queue",
Binding.DestinationType.QUEUE,
"test.direct",
"direct",
new HashMap<>())
);
}
}
SpringAMQP-RabbitMQ声明式配置使用
- 将Queue、Exchange、Binding以@Bean的方式注入到IOC容器中,同时也会在RabbitMQ服务器中创建好对应的Queue、Exchange、Binding
@Configuration
@ComponentScan({"com.rabbitmq.spring.*"})
public class RabbitMQConfiguration {
@Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setAddresses("localhost:5672");
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
connectionFactory.setVirtualHost("/");
return connectionFactory;
}
@Bean
public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
rabbitAdmin.setAutoStartup(true);
return rabbitAdmin;
}
@Bean
public TopicExchange exchange001() {
return new TopicExchange("topic001", true, true);
}
@Bean
public Queue queue001() {
return new Queue("queue001", true);
}
@Bean
public Binding binding001() {
return BindingBuilder.bind(queue001())
.to(exchange001())
.with("spring.#");
}
}
SpringAMQP - RabbitTemplate消息模板
RabbitTemplate消息模板
我们在与SpringAMQP整合时候进行发送消息的关键类,该类提供了丰富的发送消息方法,包括可靠性投递消息方法、回调监听消息接口ConfirmCallback、返回值确认接口ReturnCallback等等,同样的,在使用的时候需要先将其注入到Spring的IOC容器中。
- 注入RabbitTemplate
@Configuration
@ComponentScan({"com.rabbitmq.spring.*"})
public class RabbitMQConfiguration {
@Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setAddresses("localhost:5672");
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
connectionFactory.setVirtualHost("/");
return connectionFactory;
}
@Bean
public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
rabbitAdmin.setAutoStartup(true);
return rabbitAdmin;
}
@Bean
public TopicExchange exchange001() {
return new TopicExchange("topic001", true, true);
}
@Bean
public Queue queue001() {
return new Queue("queue001", true);
}
@Bean
public Binding binding001() {
return BindingBuilder.bind(queue001())
.to(exchange001())
.with("spring.#");
}
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
return rabbitTemplate;
}
}
- 测试RabbitTemplate的可用性
@SpringBootTest
class RabbitSpringApplicationTests {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void testMessage1() {
// 1. 创建消息的Properties部分,当然这部分也可以没有
MessageProperties messageProperties = new MessageProperties();
messageProperties.getHeaders().put("name", "snow");
messageProperties.getHeaders().put("age", 23);
// 2. 创建消息
Message message = new Message("Hello, RabbitMQ.".getBytes(), messageProperties);
// 3. 发送消息,MessagePostProcessor作用于消息发送之后的额外补充
rabbitTemplate.convertAndSend("topic001", "spring.test", message, new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
System.out.println("----消息发送后的额外信息----");
message.getMessageProperties().getHeaders().put("name", "moon");
message.getMessageProperties().getHeaders().put("sex", "female");
return message;
}
});
}
@Test
public void testMessage2() {
// 1. 创建消息的Properties部分,当然这部分也可以没有
MessageProperties messageProperties = new MessageProperties();
messageProperties.getHeaders().put("name", "snow");
messageProperties.getHeaders().put("age", 23);
// 2. 创建消息
Message message = new Message("Hello, RabbitMQ.".getBytes(), messageProperties);
// 3. 发送消息的多种方式
// 使用send方法发送消息时,表示消息的那个参数必须是Message类型
// 使用convertAndSend发送消息时,消息可以是一个Object类型,内部会转换成Message类型
rabbitTemplate.send("topic001", "spring.test1", message);
rabbitTemplate.convertAndSend("topic001", "spring.test", "Hello, RabbitMQ!");
}
}
SpringAMQP - SimpleMessageListenerContainer简单消息监听容器
SimpleMessageListenerContainer简单消息监听容器
- 这个类非常强大,我们可以对它进行很多的设置,对于消费者的配置项,这个类都可以满足
- 可以监听队列(多个队列)、自动启动、自动声明功能
- 可以设置事务特性、事务管理器、事务属性、事务容量(并发)、是否开启事务、事务回滚等
- 可以设置消息确认ACK和自动确认模式,是否重回队列requeue、异常捕获handler函数
- 设置消费者标签生成策略、是否独占模式、消费者属性等
- 另外SimpleMessageListenerContainer可以进行动态设置,比如在运行中的应用可以动态地修改其消费者数量的大小、接收消息的模式等,很多机遇RabbitMQ的自定化后端管控台在进行动态设置的时候,也是根据这个特性去实现的
@Bean
public SimpleMessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
// 设置监听的队列,可以同时监听多个队列
container.setQueues(queue001(), queue002());
// 设置当前消费者数量
container.setConcurrentConsumers(1);
// 设置最大消费者数量
container.setMaxConcurrentConsumers(5);
// 设置是否重回队列
container.setDefaultRequeueRejected(false);
// 设置消息ACK模式
container.setAcknowledgeMode(AcknowledgeMode.AUTO);
// 设置消费者标签生成策略
container.setConsumerTagStrategy(new ConsumerTagStrategy() {
@Override
public String createConsumerTag(String queue) {
return queue + "_" + UUID.randomUUID();
}
});
// 设置消息监听器
container.setMessageListener(new ChannelAwareMessageListener() {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
String msg = new String(message.getBody());
System.out.println("--消费者:" + msg);
}
});
return container;
}
SpringAMQP - MessageListenerAdapter消息适配器
在之前我们去设置消息监听器的时候,是直接new ChannelAwareMessageListener(),然后覆盖其中的onMessage方法去处理消息,除了这种消息监听器之外,还可以使用MessageListenerAdapter消息适配器的方式来处理消息
使用MessageListenerAdapter来处理消息步骤
- adapter = new MessageListenerAdapter(),实例化的时候需要指定一个委派者,也就是将消息委派给谁来进行处理,需要自己创建好这个委派类,比如new MessageListenerAdapter(new MessageDelegate())
- 通过setMessageListener(adapter)来设置来消息适配器
MessageListenerAdapter核心属性
- defaultListenerMethod默认消息监听方法名称,默认为handleMessage,可以通过这个属性的值来修改消息监听的方法名称
- Delegate委托对象:实际真实的委托对象,用于处理消息
- queueOrTagToMethodName: 队列名称或者队列标签和消息处理方法名称之间的映射,是一个Map
MessageListenerAdapter基础用法
@Bean
public SimpleMessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
// 设置监听的队列,可以同时监听多个队列
container.setQueues(queue001(), queue002());
// 设置当前消费者数量
container.setConcurrentConsumers(1);
// 设置最大消费者数量
container.setMaxConcurrentConsumers(5);
// 设置是否重回队列
container.setDefaultRequeueRejected(false);
// 设置消息ACK模式
container.setAcknowledgeMode(AcknowledgeMode.AUTO);
// 设置消费者标签生成策略
container.setConsumerTagStrategy(new ConsumerTagStrategy() {
@Override
public String createConsumerTag(String queue) {
return queue + "_" + UUID.randomUUID();
}
});
// 设置消息监听器
// MessageListenerAdapter是一个消息监听适配器,在实例化的时候需要制定一个委派者,也就是消息委派给谁处理
// 在委派者MessageDelegate中,默认使用handleMessage方法来处理消息
MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
container.setMessageListener(adapter);
return container;
}
public class MessageDelegate {
public void handleMessage(byte[] messageBody) {
System.out.println("默认方法handleMessage,消息内容为:" + new String(messageBody));
}
}
MessageListenerAdapter自定义委派者类MessageDelegate中处理消息的方法,不采用默认的handleMessage
@Bean
public SimpleMessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
// 设置监听的队列,可以同时监听多个队列
container.setQueues(queue001(), queue002());
// 设置当前消费者数量
container.setConcurrentConsumers(1);
// 设置最大消费者数量
container.setMaxConcurrentConsumers(5);
// 设置是否重回队列
container.setDefaultRequeueRejected(false);
// 设置消息ACK模式
container.setAcknowledgeMode(AcknowledgeMode.AUTO);
// 设置消费者标签生成策略
container.setConsumerTagStrategy(new ConsumerTagStrategy() {
@Override
public String createConsumerTag(String queue) {
return queue + "_" + UUID.randomUUID();
}
});
// 设置消息监听器
// MessageListenerAdapter是一个消息监听适配器,在实例化的时候需要制定一个委派者,也就是消息委派给谁处理
// 在委派者MessageDelegate中,默认使用handleMessage方法来处理消息
MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
adapter.setDefaultListenerMethod("consumerMessage");
container.setMessageListener(adapter);
return container;
}
public class MessageDelegate {
public void handleMessage(byte[] messageBody) {
System.out.println("默认方法handleMessage,消息内容为:" + new String(messageBody));
}
public void consumerMessage(byte[] messageBody) {
System.out.println("自定义字节数组方法consumerMessage,消息内容为:" + new String(messageBody));
}
}
MessageListenerAdapter自定义委派者类中消息处理方法的参数类型,也就是消息体的类型
因为默认消息体的类型是字节数组(但是如果在发送消息的时候指定了contentType为"text/plain"的话,消息体的类型就是String类型了,就可以不使用消息转换器来达到目的),如果想要使得消息处理方法的参数类型为String(也就是我们得到的消息是String类型),而不是原来的byte[]的话,就需要消息转换器MessageConverter了,这里我们可以自定义一个TextMessageConverter类来实现MessageConverter接口,主要实现其中的fromMessage
和toMessage
方法,fromMessage是要处理将消息Message转换成Java中的对象,toMessage是要处理如何将Java中的对象转换成Message。
@Bean
public SimpleMessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
// 设置监听的队列,可以同时监听多个队列
container.setQueues(queue001(), queue002());
// 设置当前消费者数量
container.setConcurrentConsumers(1);
// 设置最大消费者数量
container.setMaxConcurrentConsumers(5);
// 设置是否重回队列
container.setDefaultRequeueRejected(false);
// 设置消息ACK模式
container.setAcknowledgeMode(AcknowledgeMode.AUTO);
// 设置消费者标签生成策略
container.setConsumerTagStrategy(new ConsumerTagStrategy() {
@Override
public String createConsumerTag(String queue) {
return queue + "_" + UUID.randomUUID();
}
});
// 设置消息监听器
// MessageListenerAdapter是一个消息监听适配器,在实例化的时候需要制定一个委派者,也就是消息委派给谁处理
// 在委派者MessageDelegate中,默认使用handleMessage方法来处理消息
MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
adapter.setMessageConverter(new TextMessageConverter());
adapter.setDefaultListenerMethod("consumerMessage");
container.setMessageListener(adapter);
return container;
}
public class MessageDelegate {
public void handleMessage(byte[] messageBody) {
System.out.println("默认方法handleMessage,消息内容为:" + new String(messageBody));
}
public void consumerMessage(byte[] messageBody) {
System.out.println("自定义方法consumerMessage字节数组,消息内容为:" + new String(messageBody));
}
public void consumerMessage(String messageBody) {
System.out.println("自定义方法consumerMessage字符串,消息内容为:" + messageBody);
}
}
public class TextMessageConverter implements MessageConverter {
@Override
public Message toMessage(Object object, MessageProperties messageProperties) throws MessageConversionException {
return new Message(object.toString().getBytes(), messageProperties);
}
@Override
public Object fromMessage(Message message) throws MessageConversionException {
String contentType = message.getMessageProperties().getContentType();
if (contentType != null && contentType.contains("text")) {
return new String(message.getBody());
}
return message.getBody();
}
}
MessageListenerAdapter自定义不同的队列采用不同的消息处理方法
在MessageListenerAdapter中有一个属性为queueOrTagToMethodName,是一个Map对象,通过这个属性可以将队列名称或者队列标签和消息处理方法之间做一个映射,来实现不同队列的消息采用不同的方法去处理。
@Bean
public SimpleMessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
// 设置监听的队列,可以同时监听多个队列
container.setQueues(queue001(), queue002());
// 设置当前消费者数量
container.setConcurrentConsumers(1);
// 设置最大消费者数量
container.setMaxConcurrentConsumers(5);
// 设置是否重回队列
container.setDefaultRequeueRejected(false);
// 设置消息ACK模式
container.setAcknowledgeMode(AcknowledgeMode.AUTO);
// 设置消费者标签生成策略
container.setConsumerTagStrategy(new ConsumerTagStrategy() {
@Override
public String createConsumerTag(String queue) {
return queue + "_" + UUID.randomUUID();
}
});
// 设置消息监听器
// MessageListenerAdapter是一个消息监听适配器,在实例化的时候需要制定一个委派者,也就是消息委派给谁处理
// 在委派者MessageDelegate中,默认使用handleMessage方法来处理消息
MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
Map<String, String> queueOrTagToMethodName = new HashMap<>();
queueOrTagToMethodName.put("queue001", "method1");
queueOrTagToMethodName.put("queue002", "method2");
adapter.setQueueOrTagToMethodName(queueOrTagToMethodName);
adapter.setMessageConverter(new TextMessageConverter());
container.setMessageListener(adapter);
return container;
}
public class MessageDelegate {
public void method1(String messageBody) {
System.out.println("method1收到消息,消息内容为:" + messageBody);
}
public void method2(String messageBody) {
System.out.println("method2收到消息,消息内容为:" + messageBody);
}
}
public class TextMessageConverter implements MessageConverter {
@Override
public Message toMessage(Object object, MessageProperties messageProperties) throws MessageConversionException {
return new Message(object.toString().getBytes(), messageProperties);
}
@Override
public Object fromMessage(Message message) throws MessageConversionException {
String contentType = message.getMessageProperties().getContentType();
if (contentType != null && contentType.contains("text")) {
return new String(message.getBody());
}
return message.getBody();
}
}
SpringAMQP - MessageConverter消息转换器
MessageConverter消息转换器的作用
作用就是将接收到的消息转换成Java中的数据类型,或者将Java中的数据类型转换成Message类型,都是为了方便我们去对消息进行处理和发送,要想自定义消息转换器的话,就需要实现MessageConverter
接口,要重写里面的fromMessage
和toMessage
方法,fromMessage是要处理将消息Message转换成Java中的对象,toMessage是要处理如何将Java中的对象转换成Message
几种常见的消息转换器
- Json转换器:Jackson2JsonMessageConverter:可以实现Json(Map)和Message之间的转换
- DefaultJackson2JavaTypeMapper映射器:可以进行Java对象之间的映射关系
- 自定义二进制转换器:比如图片类型、PDF、PPT、流媒体等
几种常见的消息转换器的使用
- Json转换器:消息处理方法的参数类型为Map
@Bean
public SimpleMessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
container.setQueues(queue001(), queue002());
container.setConcurrentConsumers(1);
container.setMaxConcurrentConsumers(5);
container.setDefaultRequeueRejected(false);
container.setAcknowledgeMode(AcknowledgeMode.AUTO);
container.setConsumerTagStrategy(new ConsumerTagStrategy() {
@Override
public String createConsumerTag(String queue) {
return queue + "_" + UUID.randomUUID();
}
});
MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
adapter.setDefaultListenerMethod("consumerMessage");
Jackson2JsonMessageConverter jsonMessageConverter = new Jackson2JsonMessageConverter();
adapter.setMessageConverter(jsonMessageConverter);
container.setMessageListener(adapter);
return container;
}
public class MessageDelegate {
public void consumerMessage(Map messageBody) {
System.out.println("自定义方法consumerMessage的Map,消息内容为:" + messageBody);
}
}
@SpringBootTest
public class JsonMessageTest {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void testSendJsonMessage() throws Exception {
Order order = new Order();
order.setId(1);
order.setName("连衣裙");
order.setContent("漂亮的连衣裙");
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(order);
MessageProperties messageProperties = new MessageProperties();
messageProperties.setContentType("application/json");
Message message = new Message(json.getBytes(), messageProperties);
rabbitTemplate.send("topic001", "spring.test", message);
}
}
- DefaultJackson2JavaTypeMapper映射器,消息处理方法的参数类型为发送消息时的对象
@Bean
public SimpleMessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
container.setQueues(queue001(), queue002());
container.setConcurrentConsumers(1);
container.setMaxConcurrentConsumers(5);
container.setDefaultRequeueRejected(false);
container.setAcknowledgeMode(AcknowledgeMode.AUTO);
container.setConsumerTagStrategy(new ConsumerTagStrategy() {
@Override
public String createConsumerTag(String queue) {
return queue + "_" + UUID.randomUUID();
}
});
MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
adapter.setDefaultListenerMethod("consumerMessage");
Jackson2JsonMessageConverter jsonMessageConverter = new Jackson2JsonMessageConverter();
// 在Jackson2JsonMessageConverter的基础上再次进行了一次封装
DefaultJackson2JavaTypeMapper javaTypeMapper = new DefaultJackson2JavaTypeMapper();
// 将待转换的对象所在的包添加到javaTypeMapper的信任列表中
javaTypeMapper.setTrustedPackages("*");
jsonMessageConverter.setJavaTypeMapper(javaTypeMapper);
adapter.setMessageConverter(jsonMessageConverter);
container.setMessageListener(adapter);
return container;
}
public class MessageDelegate {
public void consumerMessage(Order messageBody) {
System.out.println("自定义方法consumerMessage的Order,消息内容为:" + messageBody);
}
}
@SpringBootTest
public class JavaMessageTest {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void testSendJavaMessage() throws Exception {
Order order = new Order();
order.setId(1);
order.setName("连衣裙");
order.setContent("漂亮的连衣裙");
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(order);
MessageProperties messageProperties = new MessageProperties();
messageProperties.setContentType("application/json");
// 指定转换的规则,也就是将消息转换成那个Java对象
messageProperties.getHeaders().put("__TypeId__", "com.rabbitmq.spring.entity.Order");
Message message = new Message(json.getBytes(), messageProperties);
rabbitTemplate.send("topic001", "spring.order", message);
}
}
- DefaultJackson2JavaTypeMapper映射器,消息处理方法的参数类型为发送消息时的对象,支持多对象映射
@Bean
public SimpleMessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
container.setQueues(queue001(), queue002());
container.setConcurrentConsumers(1);
container.setMaxConcurrentConsumers(5);
container.setDefaultRequeueRejected(false);
container.setAcknowledgeMode(AcknowledgeMode.AUTO);
container.setConsumerTagStrategy(new ConsumerTagStrategy() {
@Override
public String createConsumerTag(String queue) {
return queue + "_" + UUID.randomUUID();
}
});
MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
adapter.setDefaultListenerMethod("consumerMessage");
Jackson2JsonMessageConverter jsonMessageConverter = new Jackson2JsonMessageConverter();
// 在Jackson2JsonMessageConverter的基础上再次进行了一次封装
DefaultJackson2JavaTypeMapper javaTypeMapper = new DefaultJackson2JavaTypeMapper();
// 多对象映射配置
Map<String, Class<?>> idClassMapping = new HashMap<>();
idClassMapping.put("order", Order.class);
idClassMapping.put("order2", Order2.class);
javaTypeMapper.setTrustedPackages("*");
javaTypeMapper.setIdClassMapping(idClassMapping);
jsonMessageConverter.setJavaTypeMapper(javaTypeMapper);
adapter.setMessageConverter(jsonMessageConverter);
container.setMessageListener(adapter);
return container;
}
public class MessageDelegate {
public void consumerMessage(Order messageBody) {
System.out.println("自定义方法consumerMessage的Order,消息内容为:" + messageBody);
}
public void consumerMessage(Order2 messageBody) {
System.out.println("自定义方法consumerMessage的Order2,消息内容为:" + messageBody);
}
}
@SpringBootTest
public class JavaMessageTest {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void testSendJavaMessage() throws Exception {
Order order = new Order();
order.setId(1);
order.setName("连衣裙");
order.setContent("漂亮的连衣裙");
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(order);
MessageProperties messageProperties = new MessageProperties();
messageProperties.setContentType("application/json");
// 指定转换的规则,也就是将消息转换成那个Java对象
messageProperties.getHeaders().put("__TypeId__", "order");
Message message = new Message(json.getBytes(), messageProperties);
rabbitTemplate.send("topic001", "spring.order", message);
Order2 order2 = new Order2();
order.setId(12);
order.setName("连衣裙2");
order.setContent("漂亮的连衣裙2");
ObjectMapper mapper2 = new ObjectMapper();
String json2 = mapper2.writeValueAsString(order2);
MessageProperties messageProperties2 = new MessageProperties();
messageProperties2.setContentType("application/json");
// 指定转换的规则,也就是将消息转换成那个Java对象
messageProperties2.getHeaders().put("__TypeId__", "order2");
Message message2 = new Message(json2.getBytes(), messageProperties2);
rabbitTemplate.send("topic001", "spring.order2", message2);
}
}
- 自定义MessageConverter
ContentTypeDelegatingMessageConverter
是一个全局转换器,这个转换器中可以添加多个其他的转换器,比如之前提到的Jackson2JsonMessageConverter,TextMessageConverter
@Bean
public SimpleMessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
container.setQueues(queue001(), queue002());
container.setConcurrentConsumers(1);
container.setMaxConcurrentConsumers(5);
container.setDefaultRequeueRejected(false);
container.setAcknowledgeMode(AcknowledgeMode.AUTO);
container.setConsumerTagStrategy(new ConsumerTagStrategy() {
@Override
public String createConsumerTag(String queue) {
return queue + "_" + UUID.randomUUID();
}
});
MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
adapter.setDefaultListenerMethod("consumerMessage");
// 1. 设置全局转换器
ContentTypeDelegatingMessageConverter converter = new ContentTypeDelegatingMessageConverter();
// 2. 添加其他的转换器,对不同的消息类型做不同的处理
TextMessageConverter textConverter = new TextMessageConverter();
converter.addDelegate("text", textConverter);
converter.addDelegate("html/text", textConverter);
converter.addDelegate("xml/text", textConverter);
converter.addDelegate("text/plain", textConverter);
Jackson2JsonMessageConverter jsonMessageConverter = new Jackson2JsonMessageConverter();
converter.addDelegate("json", jsonMessageConverter);
converter.addDelegate("application/json", jsonMessageConverter);
ImageMessageConverter imageConverter = new ImageMessageConverter();
converter.addDelegate("image/png", imageConverter);
converter.addDelegate("image", imageConverter);
PDFMessageConverter pdfConverter = new PDFMessageConverter();
converter.addDelegate("application/pdf", pdfConverter);
adapter.setMessageConverter(converter);
container.setMessageListener(adapter);
return container;
}
public class ImageMessageConverter implements MessageConverter {
@Override
public Message toMessage(Object object, MessageProperties messageProperties) throws MessageConversionException {
return new Message(object.toString().getBytes(), messageProperties);
}
@Override
public Object fromMessage(Message message) throws MessageConversionException {
System.out.println("-----ImageMessageConverter-----");
Object _extName = message.getMessageProperties().getHeaders().get("extName");
String extName = _extName == null ? "png" : _extName.toString();
byte[] body = message.getBody();
String fileName = UUID.randomUUID().toString();
String path = "/Users/yan/Desktop/" + fileName + "." + extName;
File f = new File(path);
try {
Files.copy(new ByteArrayInputStream(body), f.toPath());
} catch (IOException e) {
e.printStackTrace();
}
return f;
}
}
public class PDFMessageConverter implements MessageConverter {
@Override
public Message toMessage(Object object, MessageProperties messageProperties) throws MessageConversionException {
return new Message(object.toString().getBytes(), messageProperties);
}
@Override
public Object fromMessage(Message message) throws MessageConversionException {
System.out.println("-----PDFMessageConverter-----");
byte[] body = message.getBody();
String fileName = UUID.randomUUID().toString();
String path = "/Users/yan/Desktop/" + fileName + ".pdf";
File f = new File(path);
try {
Files.copy(new ByteArrayInputStream(body), f.toPath());
} catch (IOException e) {
e.printStackTrace();
}
return f;
}
}
public class MessageDelegate {
public void consumerMessage(File messageBody) {
System.out.println("自定义方法consumerMessage的文件对象,消息内容为:" + messageBody.getName());
}
}
@SpringBootTest
public class ImageMessageTest {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void testImageMessage() throws Exception {
byte[] body = Files.readAllBytes(Paths.get("/Users/yan/壁纸", "jizhi.png"));
MessageProperties messageProperties = new MessageProperties();
messageProperties.setContentType("image/png");
messageProperties.getHeaders().put("extName", "png");
Message message = new Message(body, messageProperties);
rabbitTemplate.send("topic001", "spring.image", message);
}
@Test
public void testPDFMessage() throws Exception {
byte[] body = Files.readAllBytes(Paths.get("/Users/yan/Desktop", "1.pdf"));
MessageProperties messageProperties = new MessageProperties();
messageProperties.setContentType("application/pdf");
Message message = new Message(body, messageProperties);
rabbitTemplate.send("topic001", "spring.pdf", message);
}
}