最近在一个老项目中需要用消息队列,本来想着用卡夫卡,但是试了几个版本之后发现jdk和卡夫卡版本一直对不上,最后选择用redis来实现消息队列的发布/订阅模式。感谢这位大佬的博客给了我很多的帮助,https://www.cnblogs.com/qlqwjy/p/9763754.html再次感谢这位大佬。下面我们就看看我是怎么来实现的。
直接上代码
redis.properties
redis.url=localhost
redis.port=6379
redis.maxIdle=30
redis.minIdle=10
redis.maxTotal=100
redis.maxWait=10000
注意:url此处为了隐私改为了localhost,大家可以修改为自己的ip,如果你的redis加密了要记得在配置文件中加上redis.auth=password password是你自己设定的密码。
RedisUtil.java
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class RedisUtil {
private static JedisPool jedisPool = null;
private static Properties pro = new Properties();
//加载配置文件
static{
InputStream in = RedisUtil.class.getClassLoader().getResourceAsStream("redis.properties");
try {
pro.load(in);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//获得池子对象
JedisPoolConfig poolConfig = new JedisPoolConfig();
//最大闲置个数
poolConfig.setMaxIdle(Integer.parseInt(pro.get("redis.maxIdle").toString()));
//最大连接数
// poolConfig.setMaxTotal(Integer.parseInt(pro.get("redis.maxTotal").toString())); 2.0.0版本JedisPoolConfig没有setMaxTotal方法
poolConfig.setMaxActive(Integer.parseInt(pro.get("redis.maxTotal").toString()));
//最大等待时间
poolConfig.setMaxWait(Integer.parseInt(pro.get("redis.maxWait").toString()));
//最小闲置个数
poolConfig.setMinIdle(Integer.parseInt(pro.get("redis.minIdle").toString()));
jedisPool = new JedisPool(poolConfig,pro.getProperty("redis.url"),Integer.parseInt(pro.get("redis.port").toString()));
}
public static Jedis getJedis(){
Jedis jedis = jedisPool.getResource();
jedis.auth(pro.getProperty("redis.auth"));
return jedis;
}
//释放资源池
public static void returnSource(final Jedis jedis){
if(jedis != null){
jedisPool.returnResource(jedis);
}
}
public static void main(String[] args) {
Jedis jedis = getJedis();
System.out.println(jedis);
}
生产者代码 MessageProducer.java
import redis.clients.jedis.Jedis;
public class MessageProducer implements Runnable {
private static final String CHANNEL_KEY = "channel:1";
private volatile int count;
public void putMessage(String message){
Jedis jedis = RedisUtil.getJedis();
Long publish = jedis.publish(CHANNEL_KEY, message);//返回订阅者数量
System.out.println("------------------------"+Runnable.class.getName() + ",put message:"+message+",count=" + count +",subscriberNum=" + publish);
count++;
RedisUtil.returnSource(jedis);//释放redis资源池
}
@Override
public synchronized void run() {
for(int i = 0; i<2;i++){
putMessage("message" + count);
}
}
public static void main(String[] args) {
MessageProducer mp = new MessageProducer();
Thread t1 = new Thread(mp,"thread1");
t1.start();
}
消费者代码 MessageConsumer.java
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
public class MessageConsumer implements Runnable {
public static final String CHANNEL_KEY = "channel:1";//频道
public static final String EXIT_COMMAND = "exit";//结束程序的消息
private MyJedisPubSub jedisPubSub = new MyJedisPubSub();
public void consumerMessage(){
Jedis jedis = RedisUtil.getJedis();
jedis.psubscribe(jedisPubSub, CHANNEL_KEY);
}
@Override
public void run() {
while(true){
consumerMessage();
}
}
public static void main(String[] args) {
MessageConsumer mc = new MessageConsumer();
Thread t1 = new Thread(mc,"thread5");
Thread t2 = new Thread(mc, "thread6");
t1.start();
t2.start();
}
class MyJedisPubSub extends JedisPubSub{
@Override
public void onMessage(String channel, String message) {
// TODO Auto-generated method stub
}
@Override
public void onPMessage(String pattern, String channel, String message) {
System.out.println(Thread.currentThread().getName() + "-接受到的消息:pattern"+pattern+",channel:"+channel+",message:"+message);
String[] s = message.split(",");
for(String s1:s){
System.out.println(s1);
}
if(MessageConsumer.EXIT_COMMAND.equals(message)){
System.exit(0);
}
}
@Override
public void onSubscribe(String channel, int subscribedChannels) {
// TODO Auto-generated method stub
}
@Override
public void onUnsubscribe(String channel, int subscribedChannels) {
// TODO Auto-generated method stub
}
@Override
public void onPUnsubscribe(String pattern, int subscribedChannels) {
// TODO Auto-generated method stub
}
@Override
public void onPSubscribe(String pattern, int subscribedChannels) {
// TODO Auto-generated method stub
}
}
补充:订阅的时候subscribe()和psubscribe()的第二个参数支持可变参数,也就是可以实现订阅多个频道。