Redis消息的發佈/訂閱

以前使用redis只是用來當做非關係型數據庫來使用,提高查詢的效率。最近使用到了redis的一個新功能,redis的發佈訂閱模式。
“發佈/訂閱”(publish/subscribe)模式可以實現進程間通信,訂閱者可以訂閱一個或多個頻道(channel),而發佈者可以向指定的頻道發送消息,所有訂閱此頻道的訂閱者都會收到此消息並執行相應的操作。
redis使用RedisMessageListenerContainer進行消息監聽,客戶程序需要自己實現MessageListener,並以指定的topic註冊到RedisMessageListenerContainer,這樣,在指定的topic上如果有消息,RedisMessageListenerContainer便會通知該MessageListener。下邊演示在ssm框架下如何使用redis進行消息的發佈/訂閱。
1、spring配置文件中的配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd ">
    <!-- jedis pool配置 --> 
    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxTotal" value="${redis.maxActive}"/>
        <property name="maxIdle" value="${redis.maxIdle}"/>
        <property name="maxWaitMillis" value="${redis.maxWait}"/>
        <property name="testOnBorrow" value="${redis.testOnBorrow}"/>
    </bean>
    
    <!-- spring data redis -->  
    <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">  
        <property name="poolConfig" ref="jedisPoolConfig"></property>
		<property name="hostName" value="${redis.host}"></property>
		<property name="port" value="${redis.port}"></property>
		<property name="timeout" value="${redis.timeout}"></property>
		<property name="usePool" value="${redis.usePool}"></property> 
    </bean>  
    
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">  
        <property name="connectionFactory" ref="jedisConnectionFactory"/> 
        <property name="keySerializer">
			<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
		</property>
		<property name="valueSerializer">
			<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
		</property> 
    </bean>
    <!-- 消息接受類 -->
    <bean id="redisTestMessageListener" class="com.dongao.job.service.impl.RedisTestMessageListener"></bean>  
    <bean id="redisContainer" class="org.springframework.data.redis.listener.RedisMessageListenerContainer">
        <property name="connectionFactory" ref="jedisConnectionFactory" />
        <property name="taskExecutor"><!-- 此處有個奇怪的問題,無法正確使用其他類型的Executor -->  
            <bean class="org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler">  
                <property name="poolSize" value="2"></property>  
            </bean>  
        </property>
        <property name="messageListeners">
            <map>
                <entry key-ref="redisTestMessageListener">
                    <list>
                        <!-- 普通訂閱,訂閱具體的頻道 -->
                        <bean class="org.springframework.data.redis.listener.ChannelTopic">
                            <constructor-arg value="${redis.test.channel1}" />
                        </bean>
                        <bean class="org.springframework.data.redis.listener.ChannelTopic">
                            <constructor-arg value="${redis.test.channel2}" />
                        </bean>                       
                    </list>
                </entry>
            </map>
        </property>
    </bean> 
</beans>
配置文件中配置的是訂閱了兩個頻道。如果是3個,上邊的poolSize 配置爲3,相應的list中的bean配置爲三個。
2、發佈消息的兩個方法(頻道):
@Controller
@RequestMapping(value="demo")
public class DemoController {
	//注入redis客戶端jedis
	/*@Autowired
	private ShardJedisUtil jedisUtil;*/
	
	@SuppressWarnings("rawtypes")
	@Resource(name="redisTemplate")
	private RedisTemplate redisTemplate;
	
	@RequestMapping("/test")
	@ResponseBody
	public String test1(){
		String str="消息1";
		redisTemplate.convertAndSend(Config.redis_channel1, str);
		return "消息1發送成功!";
	}
	@RequestMapping("/test")
	@ResponseBody
	public String test2(){
		String str2="消息2";
		redisTemplate.convertAndSend(Config.redis_channel2, str2);
		return "消息2發送成功!";
	}
}
3、接收消息,執行操作的方法類:
@Component
public class RedisTestMessageListener implements MessageListener {
	@Override
	public void onMessage(Message message, byte[] pattern) {
		System.out.println("接受消息:"+message.toString());
	}
}
message中包含發送消息的頻道和消息的內容,這個時候運行的結果會直接顯示亂碼:

把接受消息的方法類修改一下,把message中的內容進行序列化,就可以顯示頻道和內容了:
@Component
public class RedisTestMessageListener implements MessageListener {
	@SuppressWarnings("rawtypes")
	@Resource(name="redisTemplate")
	private RedisTemplate redisTemplate;
	
	@Override
	public void onMessage(Message message, byte[] pattern) {
		String topic = (String)redisTemplate.getStringSerializer().deserialize(message.getChannel());
		Object body = redisTemplate.getValueSerializer().deserialize(message.getBody());  
		String msg = String.valueOf(body);
		System.out.println(topic);
		System.out.println("接受消息:"+msg);
		
	}
}
顯示結果:

  以上就是redis發佈/訂閱的簡單使用,舉個簡單的應用場景的話,以門戶網站爲例, 當編輯更新了某推薦板塊的內容後:CMS發佈清除緩存的消息到channel (推送者推送消息)門戶網站的緩存系統通過channel收到清除緩存的消息 (訂閱者收到消息),更新了推薦板塊的緩存。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章