使用Redis实现一个订阅/发布系统

使用Redis实现一个订阅/发布系统

本文所用技术简单,如有错误,对各位造成的误导,请及时联系系作者本身修正。如需转载,请注明出处,谢谢!
Redis是天生支持订阅/发布的,本文使用的技术是基于spring-redis的MessageListenerAdapter。MessageListenerAdapter的设计思路是使用代理来实现MessageListener的onMessage方法。下面先上配置:

  1. redis配置

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans" xmlns:redis="http://www.springframework.org/schema/redis"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/redis http://www.springframework.org/schema/redis/spring-redis.xsd">
    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        
        <property name="maxIdle" value="${redis.maxIdle}"/>
        
        <property name="maxTotal" value="${redis.maxTotal}"/>
        
        <property name="testOnBorrow" value="true"/>
    bean>
    <bean id="connectionFactory"
          class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <property name="hostName" value="${redis.conn.host}"/>
        <property name="port" value="${redis.conn.port}"/>
        <property name="poolConfig" ref="jedisPoolConfig"/>
        <property name="password" value="${redis.password}"/>
    bean>
    <bean id="keySerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
    <bean  id="valueSerializer" class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
        <property name="connectionFactory" ref="connectionFactory"/>
        <property name="keySerializer" ref="keySerializer"/>
        <property name="valueSerializer" ref="valueSerializer"/>
    bean>
    <bean id="messageDelegateListener" class="org.hoffman.learning.common.redis.mq.RedisMessageDelegateListener">
    bean>
    <bean id="messageListener"
          class="org.springframework.data.redis.listener.adapter.MessageListenerAdapter">
        <property name="delegate" ref="messageDelegateListener"/>
        <property name="stringSerializer" ref="keySerializer"/>
        <property name="defaultListenerMethod" value="handleMessage"/>
        <property name="serializer" ref="valueSerializer"/>
    bean>
    
    <bean id="redisContainer" class="org.springframework.data.redis.listener.RedisMessageListenerContainer">
        <property name="connectionFactory" ref="connectionFactory"/>
        <property name="messageListeners">
            <map>
                <entry key-ref="messageListener">
                    <bean class="org.springframework.data.redis.listener.ChannelTopic">
                        <constructor-arg value="test4RedisMessage"/>
                    bean>
                entry>
            map>
        property>
    bean>
beans>
  1. 发布方

方法很简单,主要是一个sendMessage方法。当然你可以根据自己的需要,抽象出一个接口来根据不同的序列化机制,用途来实现这个发布方:

public class RedisMessageSender {
  private RedisTemplate redisTemplate;
  public void sendMessage(String channel, Serializable message) {
    redisTemplate.convertAndSend(channel, message);
  }

  public RedisTemplate getRedisTemplate() {
    return redisTemplate;
  }

  public void setRedisTemplate(RedisTemplate redisTemplate) {
    this.redisTemplate = redisTemplate;
  }
}
  1. 接收方

RedisMessageDelegateListener实现了接口MessageDelegate 。作为例子,本文主要实现第四个接口,其形式如下:

public interface MessageDelegate {
//  public void handleMessage(String message);
//
//  public void handleMessage(Map message);
//
//  public void handleMessage(byte[] message);
//
//  public void handleMessage(Serializable message);

  // pass the channel/pattern as well
  public void handleMessage(Serializable message, String channel);
}

MessageDelegate 的默认实现给一个:

@Service
public class RedisMessageDelegateListener implements MessageDelegate {
@Override
  public void handleMessage(Serializable message, String channel)  {
    //什么都不做,只输出
    if(message == null){
      System.out.println("null");
    } else if(message.getClass().isArray()){
      System.out.println(Arrays.toString((Object[]) message));
    } else if(message instanceof List) {
      System.out.println(message);
    } else if(message instanceof Map) {
      System.out.println(message);
    } else {
      System.out.println(ToStringBuilder.reflectionToString(message));
    }
  }
}

写一个测试类,来测试一把

public class RedisMessagerMainThread {
  public static Logger logger = LoggerFactory.getLogger(RedisMessagerMainThread.class);

  public static void main(String[] args) {
    new ClassPathXmlApplicationContext("classpath:/applicationContext.xml");;
    while (true) {
      try {
        System.out.println("current time: " + new Date());
        Thread.sleep(3000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath*:/applicationContext.xml"})
public class RedisMessageSenderTest {
  @Autowired
  RedisMessageSender redisMessageSender;
  @Test
  public void testPublishMessage() throws Exception {
    String msg = "Hello,Redis!";
    redisMessageSender.sendMessage("test4RedisMessage", msg); //发布字符串消息
    Integer[] values = new Integer[]{21341,123123,12323};
    //这里使用的redisContainer里的topic
    redisMessageSender.sendMessage("test4RedisMessage", values);  //发布一个数组消息
  }
}

测试结果
current time: Mon May 15 11:04:17 CST 2017
[21341, 123123, 12323]
java.lang.String@39f3e025[value={H,e,l,l,o,,,R,e,d,i,s,!},hash=938209376]
current time: Mon May 15 11:04:20 CST 2017

你可能感兴趣的:(java)