redis的主要作用是提升高并发请求下的查询性能,减少查询数据库的次数,从而减轻数据库的压力。 但是随着流量的增长,传统应用在系统接口和服务处理模块层面仍然是高耦合,同步的处理方式,导致了接口由于线程堵塞而延长了整体的响应性能,即产生了高延迟。RabbitMQ就是为了解决这一问题 使用领域,服务模块解耦,异步通信,高并发限流,超时服务,数据延迟处理等。这些内容在下面会有提及
以注册登录为例,传统的业务逻辑如下 上述业务流程中,判断用户是否合法并写入数据库是其主要核心业务,而邮箱验证和发送短信验证并不是核心流程(因为你登录了,你可以后续验证),所以我们可以将邮箱验证和发送短息解耦出来,这是服务解耦
以抢购为例,抢购主要在于流量在某一时刻爆发 引入RabbitMQ后
(1)接口限流,前端对后端的请求不会立即到达后端系统,而是进入队列 (2)异步分发,当抢到商品的时候,异步发送信息
如抢火车票,如果下单后30分钟未付款,系统会自动取消该笔订单,传统的业务开发,会采用定时器的方式,每隔10秒从数据库拉取状态为0(未支付)的数据,判断当前时间是否大于30分钟,如果是就取消。 引入RabbitMQ
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(); } }