netty-socketio(二)整合redis实现发布订阅
1、Redis 发布订阅
参考:https://www.runoob.com/redis/redis-pub-sub.html
Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
Redis 客户端可以订阅任意数量的频道。
2、案例:netty-socketio和redis实现发布/订阅功能
本Demo实现:netty-socketio实现订阅(参考:https://www.cnblogs.com/xy-ouyang/p/10675904.html),redis实现推送消息。本demo保存地址:https://github.com/wenbinouyang/oy_java
demo使用 springboot 2.1.3.RELEASE,项目总体结构:

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.oy</groupId>
<artifactId>nettysocketio007</artifactId>
<version>0.0.1</version>
<name>nettysocketio008</name>
<description>nettysocketio008 for Spring Boot</description> <properties>
<java.version>1.8</java.version>
</properties> <dependencies>
<!-- spring boot start -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency> <!-- netty-socketio server -->
<dependency>
<groupId>com.corundumstudio.socketio</groupId>
<artifactId>netty-socketio</artifactId>
<version>1.7.11</version>
</dependency> <!-- springboot data redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<!-- exclusion lettuce,jedis -->
<exclusions>
<exclusion>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</exclusion>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency> <!-- jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency> <!-- jedis pool dependency -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency> <dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>
application.properties
logging.file=/home/wwwlogs/nettysocketio008/log.log #redis
#spring.redis.host=127.0.0.1
spring.redis.host=47.244.48.230
spring.redis.port=
spring.redis.password=Redis0929 spring.redis.jedis.pool.maxActive=
spring.redis.jedis.pool.max-idle=
spring.redis.jedis.pool.min-idle=
spring.redis.timeout=
Nettysocketio008Application类
package com.oy;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
import com.corundumstudio.socketio.Configuration;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.annotation.SpringAnnotationScanner; @SpringBootApplication
@Order(1)
public class Nettysocketio008Application implements CommandLineRunner {
private SocketIOServer server; public static void main(String[] args) {
SpringApplication.run(Nettysocketio008Application.class, args);
} @Bean
public SocketIOServer socketIOServer() {
Configuration config = new Configuration();
config.setHostname("localhost");
config.setPort(4001);
this.server = new SocketIOServer(config);
return server;
} @Bean
public SpringAnnotationScanner springAnnotationScanner(SocketIOServer socketServer) {
return new SpringAnnotationScanner(socketServer);
} @Override
public void run(String... args) throws Exception {
server.start();
UtilFunctions.log.info("socket.io run success!"); // 向"channel_1" push数据
// Service.send(args);
}
}
RedisConfig类
package com.oy; import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.Topic;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; @Configuration
public class RedisConfig extends CachingConfigurerSupport {
public static final Logger log = LoggerFactory.getLogger(RedisConfig.class); @Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisSerializer<String> redisSerializer = new StringRedisSerializer(); // RedisTemplate
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
template.setKeySerializer(redisSerializer);
template.setValueSerializer(redisSerializer);
template.setHashKeySerializer(redisSerializer);
template.setHashValueSerializer(redisSerializer); template.afterPropertiesSet();
return template;
} @Bean(destroyMethod = "destroy")
public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory factory,
MessageListener redisMessageListener) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(factory); ThreadPoolTaskScheduler taskExecutor = new ThreadPoolTaskScheduler();
taskExecutor.setPoolSize(10);
taskExecutor.initialize();
container.setTaskExecutor(taskExecutor); Map<MessageListener, Collection<? extends Topic>> listeners = new HashMap<>();
List<Topic> list = new ArrayList<>();
list.add(new ChannelTopic("cfd_md"));
listeners.put(redisMessageListener, list);
container.setMessageListeners(listeners); return container;
} }
MessageEventHandler类
package com.oy;
import java.util.Set;
import java.util.UUID; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import com.corundumstudio.socketio.AckRequest;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.annotation.OnConnect;
import com.corundumstudio.socketio.annotation.OnDisconnect;
import com.corundumstudio.socketio.annotation.OnEvent; @Component
public class MessageEventHandler {
public static SocketIOServer socketIoServer; @Autowired
public MessageEventHandler(SocketIOServer server) {
MessageEventHandler.socketIoServer = server;
} @OnConnect
public void onConnect(SocketIOClient client) {
UUID socketSessionId = client.getSessionId();
String ip = client.getRemoteAddress().toString();
UtilFunctions.log.info("client connect, socketSessionId:{}, ip:{}", socketSessionId, ip);
} @OnEvent("sub")
public void sub(SocketIOClient client, AckRequest request, String channel) {
UUID socketSessionId = client.getSessionId();
String ip = client.getRemoteAddress().toString();
client.joinRoom(channel);
UtilFunctions.log.info("client sub, channel:{}, socketSessionId:{}, ip:{}", channel, socketSessionId, ip); Set<String> rooms = client.getAllRooms();
for (String room : rooms) {
UtilFunctions.log.info("after client connect, room:{}", room);
} // 客户端一订阅,就马上push一次
if ("channel_1".equals(channel)) {
sendAllEvent(Service.getMsg());
} else if ("redis_channel".equals(channel)) {
sendAllEvent(RedisSub.getMsg());
}
} // @OnEvent("unsub")
// public void unsub(SocketIOClient client, AckRequest request, String channel) {
// UUID socketSessionId = client.getSessionId();
// String ip = client.getRemoteAddress().toString();
// client.leaveRoom(channel);
// UtilFunctions.log.info("client unsub, channel:{}, socketSessionId:{}, ip:{}", channel, socketSessionId, ip);
// } @OnDisconnect
public void onDisconnect(SocketIOClient client) {
UUID socketSessionId = client.getSessionId();
String ip = client.getRemoteAddress().toString();
UtilFunctions.log.info("client disconnect, socketSessionId:{}, ip:{}", socketSessionId, ip); Set<String> rooms = client.getAllRooms();
for (String room : rooms) {
UtilFunctions.log.info("after client disconnect, room:{}", room);
}
} // broadcast to channel "channel_1"
public static void sendAllEvent(String data) {
socketIoServer.getRoomOperations("channel_1").sendEvent("channel_1", data);
} // broadcast to channel "redis_channel"
public static void sendAllEvent2(String data) {
socketIoServer.getRoomOperations("redis_channel").sendEvent("redis_channel", data);
}
}
RedisSub类
package com.oy; import java.util.Date; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; @Service
public class RedisSub implements MessageListener {
private static String msg;
private String redisStr; @Autowired
private RedisTemplate<String, Object> redisTemplate; public RedisTemplate<String, Object> getRedisTemplate() {
return redisTemplate;
} @Override
public void onMessage(Message message, byte[] pattern) {
String msg = (String) redisTemplate.getValueSerializer().deserialize(message.getBody());
String channel = (String) redisTemplate.getValueSerializer().deserialize(message.getChannel()); if (null != channel && !"".equals(channel) && null != msg && !"".equals(msg)) { // 相同数据不push
if(redisStr == null) {
UtilFunctions.log.info("===== redisStr == null =====");
redisStr = msg;
} else if (redisStr.equals(msg)) {
UtilFunctions.log.info("===== redisStr is same =====");
return ;
} else {
UtilFunctions.log.info("===== redisStr:{} =====", redisStr);
redisStr = msg;
} JSONObject data = new JSONObject();
JSONObject json = JSON.parseObject(msg);
data.put(json.getString("contract"), json); JSONObject jsonObj = new JSONObject();
jsonObj.put("channel", channel);
jsonObj.put("timestamp", new Date().getTime());
jsonObj.put("data", data); MessageEventHandler.sendAllEvent2(jsonObj.toJSONString());
RedisSub.msg = jsonObj.toJSONString();
UtilFunctions.log.info("message from channel:{}, msg:{} ", channel, jsonObj.toJSONString());
} } public static String getMsg() {
return msg;
} public static void setMsg(String msg) {
RedisSub.msg = msg;
}
}
客户端html页面及测试参考:https://www.cnblogs.com/xy-ouyang/p/10675904.html
netty-socketio(二)整合redis实现发布订阅的更多相关文章
- (二)Redis 笔记——发布&订阅、事务、数据库操作
1. Redis 发布订阅 1.1 概述 Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息. Redis 客户端可以订阅任意数量的频道. 下 ...
- redis(3)发布订阅
一.发布/订阅模式 在软件工程里面,发布/订阅是一种消息模式,这种模式旨在将消息发送者和消息接收者解耦.发送者不需要关心将消息发送给谁,接收者也不需要知道消息的发送者是谁.发送者将消息发布以后就结束动 ...
- StackExchange.Redis 使用-发布订阅 (二)
使用Redis的发布订阅功能 redis另一个常见的用途是发布订阅功能 . 它非常的简单 ,当连接失败时 ConnectionMultiplexer 会自动重新进行订阅 . ISubscriber s ...
- redis 实现发布订阅的功能
redis 除了作为缓存的功能外还可以用作消息中间件的功能,这片博客主要是介绍一下 redis 整合spring 实现消息的发布和订阅功能: 1:redis依赖,依赖两个包,redis 包, spri ...
- Redis之发布订阅
一 什么是发布订阅 发布订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都将得到通知 Redis 发布订阅(pub/sub)是一种消息通信模式: ...
- [翻译] C# 8.0 新特性 Redis基本使用及百亿数据量中的使用技巧分享(附视频地址及观看指南) 【由浅至深】redis 实现发布订阅的几种方式 .NET Core开发者的福音之玩转Redis的又一傻瓜式神器推荐
[翻译] C# 8.0 新特性 2018-11-13 17:04 by Rwing, 1179 阅读, 24 评论, 收藏, 编辑 原文: Building C# 8.0[译注:原文主标题如此,但内容 ...
- 【spring boot】【redis】spring boot 集成redis的发布订阅机制
一.简单介绍 1.redis的发布订阅功能,很简单. 消息发布者和消息订阅者互相不认得,也不关心对方有谁. 消息发布者,将消息发送给频道(channel). 然后是由 频道(channel)将消息发送 ...
- Springboot+Redis(发布订阅模式)跨多服务器实战
一:redis中发布订阅功能(http://www.redis.cn/commands.html#pubsub) PSUBSCRIBE pattern [pattern -]:订阅一个或者多个符合pa ...
- redis的发布订阅模式
概要 redis的每个server实例都维护着一个保存服务器状态的redisServer结构 struct redisServer { /* Pubsub */ // 字典,键为频道, ...
随机推荐
- vue如何实现热更新
我们都知道,对于node来说,前端vue代码的迭代节奏是很快的,可能一周要迭代几次,但是node的迭代却没那么平凡,可能一周更新一次甚至更久,那么为了node服务的稳定,减少node服务的发布次数,是 ...
- 交换机安全学习笔记 第九~十章 HSRP VRRP
HSRP (Hot Standby Router Protocol) 热备份路由器协议 思科私有 HSRP消息使用UDP 端口号 1985(IPv6时为2029) 使用多播地址 224.0.0.2( ...
- hue的load balance
参考: hue的load balance官网: https://www.cloudera.com/documentation/enterprise/6/6.2/topics/hue_use_add_l ...
- 【6.12校内test】T1单词序列
[问题描述] 给出两个单词(开始单词和结束单词)以及一个词典.找出从开始单词转换到结束单词, 所需要的最短转换序列.转换的规则如下: 1.每次只能改变一个字母 2.转换过程中出现的单词(除开始单词和结 ...
- 【6.18校内test】T3细胞分裂
尽管T1T2很简单,但还是阻止不了我T3wa一片 细胞分裂[题目链接] xcg同学有一个80pts的代码 他说他的代码和我的很像,可惜我比较笨,只有30pts 其实这道题考场上是想到要分解质因数了,然 ...
- P5596 洛谷月赛 题 题解
因为a>=0,b>=0,所以y^2-x^2>=0,所以y>x,因为都是自然数设y=x+k,化简得x=b-k^2/2*k-a;可知x仅当b-k^2%2*k-a==0且b-k^2与 ...
- AtCoder Beginner Contest 077
A - Rotation Time limit : 2sec / Memory limit : 256MB Score : 100 points Problem Statement You are g ...
- javaweb:关于HttpServletResponse介绍 (转)
出处: https://www.cnblogs.com/xdp-gacl/p/3789624.html Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request ...
- [.net core] 12.环境变量
异常给开发人员提供了很大好的排错功能. 但是其背后的技术细节很复杂,会损耗性能,也会使.net core web app更容易被反派攻击. 于是我们要学会使用环境变量, 通过环境变量,控制一些逻辑 当 ...
- luogu P4382 [九省联考2018]劈配
luogu 我记得我第一次做这道题的时候屁都不会qwq 先考虑第一问,暴力是依次枚举每个人,然后从高到低枚举志愿,枚举导师,能选就选.但是可以发现前面的人选的导师可能会导致后面的人本来可以选到这个志愿 ...