redis订阅发布模式简单使用

redis订阅发布模式简单使用

Spring订阅发布模式
  • Spring自带的一套订阅发布模式,可惜不支持项目集群,功能没那么强大。

  • 简单使用

    • 消息发布者:注入Spring全局事件发布对象

      @Service
      public class BootMessagePublisher {
      
          private static final Logger log = LoggerFactory.getLogger(MessagePublisher.class);
      
          @Resource
          private ApplicationEventPublisher applicationEventPublisher;
      
          
          public void register(){
              log.info("开始注册了......");
              BootMessageBo bo = BootMessageBo.create();
              bo.setType(1);
              bo.setMsg("用户注册");
              bo.setPublisher(1307282660L);
              bo.addListener(1234567890L);
              bo.setBootMessage("使用BootMessageBo类发送信息");
              // 发布 --- 注意此时发布的类型 为 MessageBo的子类
              applicationEventPublisher.publishEvent(bo);
              log.info("注册结束了......");
          }
      }
      
    • 消息订阅者:标注@EventListener注解 (也可通过实现ApplicationListener 接口获取订阅功能)

      @Component
      public class BootMessageListener {
      
          private static final Logger log = LoggerFactory.getLogger(MessageListener.class);
          // 这个是自定义的消息处理器 不用管
          // 可以直接打印bo对象就行 
          @Resource(name = "bootProcesser")
          private BaseProcesser baseProcesser;
      
          /**
           * 发送事件的类型是啥 参数就是啥 相当于监听这个 发送事件的类型
           * @param bo 这个是自定义的监听对象
           */
          @EventListener
          public void listen(MessageBo bo){
              baseProcesser.processer(bo);
          }
      }
      

      Spring的一个订阅会监听一种类型(包括其子类),所有监听该类型的事件都会收到通知

    • 自定义监听对象(顶级父类 省略getter setter)

      public class MessageBo implements Serializable {
      
          public String msg;
          public Integer type;
          public Long publisher;
          public List<Long> listeners;
          // 重写此方法是为了解决子类无法输出全部属性的问题(无需转型)
          @Override
          public String toString() {
              return JSONObject.toJSONString(this);
          }
      }
      
    • Springboot的自定义监听对象

      public class BootMessageBo extends MessageBo {
          private String bootMessage;
      }
      
  • 前期工作准备好之后 直接开始调用 qaq

    @SpringBootApplication
    public class TestApplication {
        public static void main(String[] args){
        	// 获取容器对象
            ConfigurableApplicationContext context = SpringApplication.run(TestApplication.class, args);
            // 获取我们定义的消息发布者
            BootMessagePublisher publisher = context.getBean(BootMessagePublisher.class);
            // 开---调!
            publisher.register();
       }
    }
    // 不会放图片 直接复制输出结果...
    2022-10-13 14:48:22.062  INFO 18500 --- [           main] com.pzz.grow.MessagePublisher            							   : 开始注册了......
    2022-10-13 14:48:22.062  INFO 18500 --- [           main] c.pzz.grow.biz.processer.BaseProcesser   : 信息发送者---->130xxxxxxx
    2022-10-13 14:48:22.062  INFO 18500 --- [           main] c.pzz.grow.biz.processer.BaseProcesser   : 消息---->用户注册
    2022-10-13 14:48:22.062  INFO 18500 --- [           main] c.pzz.grow.biz.processer.BaseProcesser   : 消息类型---->1
    2022-10-13 14:48:22.062  INFO 18500 --- [           main] c.pzz.grow.biz.processer.BaseProcesser   : 信息接收者---->[1234567890]
    2022-10-13 14:48:22.062  INFO 18500 --- [           main] 
    c.pzz.grow.biz.processer.BaseProcesser   : 使用BootMessageBo类发送信息
    2022-10-13 14:48:22.063  INFO 18500 --- [           main] c.pzz.grow.biz.processer.BaseProcesser   : 普通注册
    2022-10-13 14:48:22.063  INFO 18500 --- [           main] com.pzz.grow.MessagePublisher            							   : 注册结束了......
    
redis 订阅发布模式

​ 开搞开搞!

  • 先把redis 配置好…

       @Configuration
    public class RedisConfig {
    
        @Value("${other.redis.channel1}")
        private String channel;
        @Value("${other.redis.channel2}")
        private String channel2;
        @Value("${spring.redis.host}")
        private String host;
        @Value("${spring.redis.port}")
        private int port;
        @Value("${spring.redis.timeout}")
        private int timeout;
        /**
         * redis配置
         *
         * @author MinghanSui
         * 为null的属性值不会存入redis
         * 转自:https://blog.51cto.com/u_15089769/2602942
         */
        @Bean("selfRedisTemplate")
        public RedisTemplate<String, Object> selfRedisTemplate(RedisConnectionFactory connectionFactory) {
            RedisTemplate<String, Object> template = new RedisTemplate<>();
            template.setConnectionFactory(connectionFactory);
    
            StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
            SelfRedisSerializer myRedisSerializer = new SelfRedisSerializer(Object.class);
    
            template.setKeySerializer(stringRedisSerializer);
            // 自定义序列化
            template.setValueSerializer(myRedisSerializer);
    
            template.setHashKeySerializer(stringRedisSerializer);
            // 自定义序列化
            template.setHashValueSerializer(myRedisSerializer);
    
            template.afterPropertiesSet();
            return template;
        }
        
        @Bean
        public RedisMessageListener redisMessageListener() {
        	// 配置使用我们自定义的消息监听器
            return new RedisMessageListener();
        }
    
        @Bean
        public ChannelTopic channel() {
        	// 配置监听管道
            return new ChannelTopic(channel);
        }
    
        @Bean("channel2")
        public ChannelTopic channel2() {
            return new ChannelTopic(channel2);
        }
        
       /** 复制的
         * RedisMessageListenerContainer 为Redis消息侦听器 MessageListener 提供异步行为的容器。处理侦听、转换和消息分派的低级细节。
         * 与低级别Redis(每个订阅一个连接)相反,容器只使用一个连接,该连接对所有注册的侦听器都是“多路复用”的,消息调度是通过任务执行器完成的。
         * 注意:容器以惰性方式使用连接(仅当至少配置了一个侦听器时才使用连接)。
         * 同时添加和删除侦听器会产生未定义的结果。强烈建议对这些方法进行相应的同步/排序。
         * 转自:https://www.cnblogs.com/kendoziyu/p/15807337.html
         */
        @Bean
        public RedisMessageListenerContainer messageListenerContainer(RedisConnectionFactory redisConnectionFactory) {
            RedisMessageListenerContainer container = new RedisMessageListenerContainer();
            container.setConnectionFactory(redisConnectionFactory);
            // 这里可以配置 哪个类监听哪条管道
            container.addMessageListener(redisMessageListener(), channel());
            return container;
        }
        
       /**
         * 自定义Redis序列化
         * @author MinghanSui
         * 转自:https://blog.51cto.com/u_15089769/2602942
         */
        public static class SelfRedisSerializer<T> implements RedisSerializer<T> {
            public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
            private Class<T> clazz;
            static {
                ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
            }
            public SelfRedisSerializer(Class<T> clazz) {
                super();
                this.clazz = clazz;
            }
            @Override
            public byte[] serialize(T t) throws SerializationException {
                if (t == null) {
                    return new byte[0];
                }
                return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
            }
            @Override
            public T deserialize(byte[] bytes) throws SerializationException {
                if (bytes == null || bytes.length <= 0) {
                    return null;
                }
                String str = new String(bytes, DEFAULT_CHARSET);
                return JSON.parseObject(str, clazz);
            }
        }
    }
    
  • yml 配置文件

      spring:
        redis:
          timeout: 5000
          host: 192.168.222.11
          port: 6379
          database: 0
          password: 123456
      other:
        redis:
          channel1: xxx
          channel2: yyy    
    
  • 消息发布者

    @Service
    public class RedisMessagePubliser{
    
        @Resource(name = "selfRedisTemplate")
        private RedisTemplate<String, Object> selfRedisTemplate;
        @Resource(name = "channel")
        private ChannelTopic channel;
    
        @Override
        public void register() {
            MessageBo bo = new MessageBo();
            bo.setMsg("测试一下");
            // 向管道中发送信息
            selfRedisTemplate.convertAndSend(channel.getTopic(), bo);
        }
    
        public static RedisMessagePubliser curr(){
            return SpringContentUtils.getBean(RedisMessagePubliser.class);
        }
    }
    
  • 消息订阅者

    public class RedisMessageListener implements MessageListener {
    	// 获取管道中的信息
        @Override
        public void onMessage(Message message, byte[] pattern) {
            String obj = new String(message.getBody());
            System.out.println(obj);
        }
    }
    

    至此大功告成,开调!

@SpringBootApplication
public class TestApplication {
    public static void main(String[] args){
    	// 获取容器对象
        ConfigurableApplicationContext context = SpringApplication.run(TestApplication.class, args);
        // 获取我们定义的消息发布者
        RedisMessagePublisher publisher = context.getBean(RedisMessagePublisher.class);
        // 开---调!
        publisher.register();
   }
}
// 输出结果
{"@type":"com.pzz.grow.biz.bo.MessageBo","msg":"测试一下"}

具体的一些解释,原理可自行百度参考别的博客,另外,欢迎各位大佬指出错误与不足之处qaq。

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值