最近在一个老项目中需要用消息队列,本来想着用卡夫卡,但是试了几个版本之后发现jdk和卡夫卡版本一直对不上,最后选择用redis来实现消息队列的发布/订阅模式。感谢这位大佬的博客给了我很多的帮助,再次感谢这位大佬。下面我们就看看我是怎么来实现的。

直接上代码
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()的第二个参数支持可变参数,也就是可以实现订阅多个频道。