本文建立在RabbitMQ和Redis都安装好,并服务已经都启动的前提下进行的。模拟的场景是分布式下一个中心发送消息,另一个中心接受消息并向Redis中作处理以及限流,即短时间之类发送重复消息将不会处理。项目中可模拟用户登录时发送手机验证码,只不过本文没有写发送短信的代码。
- 准备条件
生产者依赖及相关配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
server:
port: 8081
spring:
rabbitmq:
host: 192.168.157.132
username: CandySir
password: CandySir
virtual-host: /CandySir
template:
retry:
enabled: true
initial-interval: 10000ms
max-interval: 30000ms
multiplier: 2
exchange: ly.item.exchange
publisher-confirms: true
消费者依赖及相关配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
server:
port: 8082
spring:
rabbitmq:
host: 192.168.157.132
username: CandySir
password: CandySir
virtual-host: /CandySir
redis:
host: 192.168.157.132
- 具体代码
生产者Controller
@Autowired
private GoodsService goodsService;
@PostMapping("test")
public void test(){
goodsService.test();
}
生产者Service
@Autowired
private AmqpTemplate amqpTemplate;
public void test(){
amqpTemplate.convertAndSend("item.update","1");
}
消费者监听
@Component
@Slf4j
public class ItemListener {
@Autowired
private UploadService uploadService;
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "search.item.insert.queue", durable = "true"),
exchange = @Exchange(name = "ly.item.exchange", type = ExchangeTypes.TOPIC),
key = {"item.insert", "item.update"}
))
public void listenInsertOrUpdate(String id){
log.info("接收到消息:" + id);
uploadService.testRedis(id);
}
}
消费者service
@Service
@Slf4j
public class UploadService {
@Autowired
private StringRedisTemplate stringRedisTemplate;
private static final List<String> ALLOW_TYPES = Arrays.asList("image/png", "image/jpeg");
public String testRedis(String id) {
String key = "CandySir:" + id;
String lastTime = stringRedisTemplate.opsForValue().get(key);
//判断key是否重复,如果相同,在判断是否存活,存活不作处理,不存活就执行业务代码
if(StringUtils.isNotBlank(lastTime)){
Long last = Long.valueOf(lastTime);
if(System.currentTimeMillis() - last < 60000){
log.info("发送评率过高,请稍后再试。");
return null;
}
}
//此处省略,可做业务代码处理
//向redis存入key并设置1分钟的存活时间
stringRedisTemplate.opsForValue().set(key,String.valueOf(System.currentTimeMillis()),1, TimeUnit.MINUTES);
log.info("发送成功");
return null;
}
}
- 测试
访问生产者Controller,发送消息
此时查看redis里key所剩的存活时间还有46秒
再次访问生产者Controller,发送消息。由于我是设置的存活时间是一分钟,所以一分钟之内发送相同的消息,就会检测发送评率过高。相同的消息我是用key来做判断的。
此时查看redis里key所剩的存活时间还有41秒
等过了一分钟之后再次查看key,就没有了。此时再次发送消息,redis就会做处理了。跟第一步测试一样。