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。