生产者消费者模式之Redis实现的消息队列代码原理
Redis提供了两种方式来作消息队列。
一个是使用生产者消费模式模式,
另一个就是发布订阅者模式。
前者会让一个或者多个客户端监听消息队列,一旦消息到达,消费者马上消费,谁先抢到算谁的,如果队列里没有消息,则消费者继续监听。
后者也是一个或多个客户端订阅消息频道,只要发布者发布消息,所有订阅者都能收到消息,订阅者都是平等的。
本文采用的是生产者消费者模式。
基于Redis的消息队列实现的异步操作原理图如下:
把很多模块的某些非主业务的操作都进行异步处理。
再比如订单模块中用户下单的过程,下单成功后,发送短信等非主要业务。直接把这些操作写在一个handle里。然后先返回直接返回结果,然后再通过异步处理给用户发送下单成功的信息。
EventProducer将事件推送到消息队列中,
EventConsumer监听队列,只要监测到有事件到达,就将事件取出,交给对应的Handler进行处理。
异步队列总结:
- 使用redis的列表作为队列,lpush、rpop
- EventProducer:生产者,负责把事件模型添加到队列中。如点赞操作时,在点赞操作接口生成生产者类,在点赞操作时,调用类中fireEvent(EventModel model)方法将点赞事件添加到Redis队列中。
- EventModel:事件模型,里面包含事件的类型和事件对应的数据,序列化存储在队列中
- EventType:事件类型,Enum,点赞、评论、邮件、登陆分别对应不同的枚举值
- EventHandler:接口,提供handler()、getSupportedTypes()两个方法()。
- LikeHandler:继承EventHandler接口,提供处理方法和支持多种类型的事件
- EventConsumer:消费者,设计是一个事件模型传过来,获取它的事件类型,根据事件的。
--》先将所有的Handler注册了,在消费者类初始化时Map<String,EventHandler> beans = applicationContext.getBeansOfType(EventHandler.class)找出所有Handler。
--》设置一个事件处理Map,key为事件类型,value为该事件类型需要的Handler。
--》遍历Handler,将对应的key、value放入事件处理Map中。
--》再在初始化时,开启一个线程,该线程一直从(死循环)Redis队列中取出事件模型,根据事件类型找到对应的Handler进行处理。
代码实现
1.Redis数据库的底层操作:
将事件序列化后存入数据库;从数据库获取事件:
package com.wgs.mailSender.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.List;
/**
* Created by wanggenshen_sx on 2017/5/9.
*/
Service
publicclass JedisAdapter implements InitializingBean{
private
static
final
Logger logger = LoggerFactory.getLogger(JedisAdapter.class);
private
Jedis jedis =
null;
private
JedisPool jedisPool =
null;
/**
* 初始化
* @throws Exception
*/
@Override
public
void
afterPropertiesSet
()
throwsException {
jedisPool =
newJedisPool(
"localhost",
6379);
}
/**
* 从JedisPool获取一个Jedis连接
* @return
*/
private
Jedis
getJedis(){
try
{
jedis = jedisPool.getResource();
return
jedis;
}
catch(Exception e){
logger.error(
"获取Jedis 异常 :"+ e.getMessage());
return
null
;
}
finally{
if
(jedis !=
null){
try
{
jedis.close();
}
catch(Exception e){
logger.error(e.getMessage());
}
}
}
}
/**
* 存入List集合中
* @param key
* @param value
* @return
*/
public
long
lpush
(String key, String value){
Jedis jedis =
null;
try
{
jedis = jedisPool.getResource();
long
result = jedis.lpush(key, value);
return
result;
}
catch(Exception e){
logger.error(
"Jedis lpush 异常 :"+ e.getMessage());
return
0
;
}
finally{
if
(jedis !=
null){
try
{
jedis.close();
}
catch(Exception e){
logger.error(e.getMessage());
}
}
}
}
/**
* 获取指定值
* @param timeout
* @param key
* @return
*/
&nb