这里还是采用用户注册后发送邮件和短信为例来说明:
生产者代码
package com.infosys.china.producer;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component
public class FanoutConfig
{
// 邮件队列
private String FANOUT_EMAIL_QUEUE = "fanout_email_queue";
// 短信队列
private String FANOUT_SMS_QUEUE = "fanout_sms_queue";
// 定义交换机
private String EXCHANGE_NAME = "fanoutExchange";
// 1.定义邮件队列
@Bean
public Queue fanOutEmailQueue()
{
return new Queue(FANOUT_EMAIL_QUEUE);
}
// 1.定义短信队列
@Bean
public Queue fanOutSmsQueue()
{
return new Queue(FANOUT_SMS_QUEUE);
}
// 2.定义交换机
@Bean
public FanoutExchange fanoutExchange()
{
return new FanoutExchange(EXCHANGE_NAME);
}
// 3.队列与交换机绑定邮件队列
@Bean
Binding bindingExchangeEamil(Queue fanOutEmailQueue, FanoutExchange fanoutExchange)
{
return BindingBuilder.bind(fanOutEmailQueue).to(fanoutExchange);
}
// 4.队列与交换机绑定短信队列
@Bean
Binding bindingExchangeSms(Queue fanOutSmsQueue, FanoutExchange fanoutExchange)
{
return BindingBuilder.bind(fanOutSmsQueue).to(fanoutExchange);
}
}
package com.infosys.china.producer;
import java.util.Date;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
*
* 生产者发送消息
*
* @author Jiayoubing
* @version [版本号,2020年5月7日]
* @see [相关类/方法]
* @since [产品/模块版本]
*/
@Component
public class FanoutProducer
{
@Autowired
private AmqpTemplate amqpTemplate;
public void send(String queueName)
{
String msg = "my_fanout_msg:" + new Date();
System.out.println("msg is :" + msg);
amqpTemplate.convertAndSend(queueName, msg);
}
}
package com.infosys.china.producer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ProducerController
{
@Autowired
private FanoutProducer fanoutProducer;
@RequestMapping("/sendFanout")
public String sendFanout(String queueName)
{
fanoutProducer.send(queueName);
return "success";
}
}
POM文件
org.springframework.boot
spring-boot-starter-parent
2.1.7.RELEASE
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-amqp
org.apache.commons
commons-lang3
com.alibaba
fastjson
1.2.49
3.1.1
/**
* 文件名:AppProducer.java 版权:Company Technologies Co.,Ltd.Copyright YYYY-YYYY,All
* rights reserved 版权:Copyright (c) 2020, [email protected] All Rights
* Reserved. 描述:<描述> 修改人:Administrator 修改时间:2020年5月7日 修改内容:<修改内容>
*/
package com.infosys.china.producer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
/**
* <一句话功能简述> <功能详细描述>
*
* @author Jiayoubing
* @version [版本号,2020年5月7日]
* @see [相关类/方法]
* @since [产品/模块版本]
*/
@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
public class AppProducer
{
public static void main(String[] args) throws Exception
{
SpringApplication.run(AppProducer.class, args);
}
}
消费者代码
/**
* 文件名:AppConsumer.java 版权:Company Technologies Co.,Ltd.Copyright YYYY-YYYY,All
* rights reserved 版权:Copyright (c) 2020, [email protected] All Rights
* Reserved. 描述:<描述> 修改人:Administrator 修改时间:2020年5月7日 修改内容:<修改内容>
*/
package com.infosys.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
/**
* <一句话功能简述> <功能详细描述>
*
* @author Jiayoubing
* @version [版本号,2020年5月7日]
* @see [相关类/方法]
* @since [产品/模块版本]
*/
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class AppConsumer
{
public static void main(String[] args) throws Exception
{
SpringApplication.run(AppConsumer.class, args);
}
}
package com.infosys.consumer;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
@RabbitListener(queues = "fanout_email_queue")
public class FanoutEamilConsumer {
@RabbitHandler
public void process(String msg) throws Exception {
System.out.println("邮件消费者获取生产者消息msg:" + msg);
}
}
package com.infosys.consumer;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
@RabbitListener(queues = "fanout_sms_queue")
public class FanoutSmsConsumer {
@RabbitHandler
public void process(String msg) {
System.out.println("短信消费者获取生产者消息msg:" + msg);
}
}
在启动生产者和消费者之前,需要先创建交货机和队列
执行结果:
spring:
rabbitmq:
####连接地址
host: 192.168.234.103
####端口号
port: 5672
####账号
username: guest
####密码
password: guest
### 地址
virtual-host: /
listener:
simple:
retry:
###开启消费者重试
enabled: true
###重试次数
max-attempts: 5
###重试间隔时间
initial-interval: 3000
###手动开启ack应答模式
acknowledge-mode: manual
代码加上手动应答机制:
package com.infosys.consumer;
import java.util.Map;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Headers;
import org.springframework.stereotype.Component;
import com.rabbitmq.client.Channel;
@Component
@RabbitListener(queues = "fanout_email_queue")
public class FanoutEamilConsumer
{
@RabbitHandler
public void process(String msg, @Headers Map headers, Channel channel) throws Exception
{
System.out.println("邮件消费者获取生产者消息msg:" + msg);
// 手动ack
Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
// 手动签收
channel.basicAck(deliveryTag, false);
}
}
如何解决消费者重复消费的问题?
解决办法:在生产者里面传一个唯一的消息id或者业务id(这个id必须为唯一性的),在消费者里面判断这个id是否已执行,如果没有执行,就处理,如果执行直接返回成功。
Message message = MessageBuilder.withBody(msg.getBytes()).setContentType(MessageProperties.CONTENT_TYPE_JSON)
.setContentEncoding("utf-8").setMessageId(UUID.randomUUID() + "").build();