概述
redis的主要作用是提升高并发请求下的查询性能,减少查询数据库的次数,从而减轻数据库的压力。
但是随着流量的增长,传统应用在系统接口和服务处理模块层面仍然是高耦合,同步的处理方式,导致了接口由于线程堵塞而延长了整体的响应性能,即产生了高延迟。RabbitMQ就是为了解决这一问题
使用领域,服务模块解耦,异步通信,高并发限流,超时服务,数据延迟处理等。这些内容在下面会有提及
典型的应用场景介绍
异步通信和服务解耦
以注册登录为例,传统的业务逻辑如下
上述业务流程中,判断用户是否合法并写入数据库是其主要核心业务,而邮箱验证和发送短信验证并不是核心流程(因为你登录了,你可以后续验证),所以我们可以将邮箱验证和发送短息解耦出来,这是服务解耦
接口限流和消息分发
以抢购为例,抢购主要在于流量在某一时刻爆发
引入RabbitMQ后
(1)接口限流,前端对后端的请求不会立即到达后端系统,而是进入队列
(2)异步分发,当抢到商品的时候,异步发送信息
延迟处理
如抢火车票,如果下单后30分钟未付款,系统会自动取消该笔订单,传统的业务开发,会采用定时器的方式,每隔10秒从数据库拉取状态为0(未支付)的数据,判断当前时间是否大于30分钟,如果是就取消。
引入RabbitMQ
基于Spring的事件驱动模型实战
spring的事件驱动,就是事件驱动实现业务之间的交互,交互的方式有同步和异步两种,事件也可称之为消息
在传统的spring应用系统中,没有RabbitMQ之前,是就是通过事件驱动模型解耦业务和异步通信的,这个现在的RabbitMQ有着几分相似之处
接下来要实现一个Spring的事件驱动,需求为,用户登录成功后的相关信息封装成实体对象,由生产者采用异步的方式发布给消费者,当消费者监听到消息时,执行相应的业务处理逻辑。
package com.learn.boot.event;
import lombok.Data;
import lombok.ToString;
import org.springframework.context.ApplicationEvent;
import java.io.Serializable;
/**
* zlx
* 用户登录成功后的消息
*/
@ToString
public class LoginEvent extends ApplicationEvent implements Serializable {
/**
* 登录名
*/
private String userName;
/**
* 登录ip
*/
private String ip;
/**
* 登录时间
*/
private String loginTime;
public LoginEvent(Object source) {
super(source);
}
/** 重构构造方法
* @param source
* @param ip
* @param loginTime
* @param userName
*/
public LoginEvent(Object source,String ip,String loginTime,String userName) {
super(source);
this.ip = ip;
this.loginTime = loginTime;
this.userName = userName;
}
}
package com.learn.boot.event;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;
/**
* 事件模型的消费者
*/
@Component
@EnableAsync //允许异步执行
public class Consumer implements ApplicationListener<LoginEvent> {
private static final Logger log = LoggerFactory.getLogger(Consumer.class);
/** 监听的方法
* @param loginEvent
*/
@Override
@Async
public void onApplicationEvent(LoginEvent loginEvent) {
//输出日志信息
log.info("Spring事件驱动模型-接收消息:{}",loginEvent);
//TODO:后续为实现自身的业务逻辑,如写入数据库等
}
}
package com.learn.boot.event;
import org.apache.catalina.core.ApplicationPushBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
/** zlx
* 事件模型发送者
*/
@Component
public class Producer {
private static final Logger log= LoggerFactory.getLogger(Producer.class);
@Autowired
private ApplicationEventPublisher pushBuilder;
public void sendMesg() throws Exception {
// 构造登录以后的实体对象
LoginEvent event=new LoginEvent(this,"debug",new SimpleDateFormat
("yyyyy-MM-dd HH:mm:ss").format(new Date()),"127.0.0.1");
//发送消息
pushBuilder.publishEvent(event);
log.info("发送者发送对象{}",event);
}
}
package com.learn.boot;
import com.learn.boot.event.Producer;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class BootApplicationTests {
@Autowired
Producer producer;
@Test
void contextLoads() throws Exception {
// 调用发送者测试
producer.sendMesg();
}
}