forked from yudaocode/SpringBoot-Labs
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
YunaiV
committed
Jun 18, 2020
1 parent
558c495
commit 0ba1edb
Showing
20 changed files
with
608 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
<?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"> | ||
<parent> | ||
<artifactId>lab-67-netty-demo</artifactId> | ||
<groupId>cn.iocoder.springboot.labs</groupId> | ||
<version>1.0-SNAPSHOT</version> | ||
</parent> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<artifactId>lab-67-netty-demo-client</artifactId> | ||
|
||
<properties> | ||
<!-- 依赖相关配置 --> | ||
<spring.boot.version>2.2.4.RELEASE</spring.boot.version> | ||
<!-- 插件相关配置 --> | ||
<maven.compiler.target>1.8</maven.compiler.target> | ||
<maven.compiler.source>1.8</maven.compiler.source> | ||
</properties> | ||
|
||
<dependencyManagement> | ||
<dependencies> | ||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-parent</artifactId> | ||
<version>${spring.boot.version}</version> | ||
<type>pom</type> | ||
<scope>import</scope> | ||
</dependency> | ||
</dependencies> | ||
</dependencyManagement> | ||
|
||
<dependencies> | ||
<!-- 实现对 Spring MVC 的自动化配置 --> | ||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-web</artifactId> | ||
</dependency> | ||
|
||
<!-- Netty 依赖 --> | ||
<dependency> | ||
<groupId>io.netty</groupId> | ||
<artifactId>netty-all</artifactId> | ||
<version>4.1.50.Final</version> | ||
</dependency> | ||
|
||
<!-- 引入 netty-demo-common 封装 --> | ||
<dependency> | ||
<groupId>cn.iocoder.springboot.labs</groupId> | ||
<artifactId>lab-67-netty-demo-common</artifactId> | ||
<version>1.0-SNAPSHOT</version> | ||
</dependency> | ||
</dependencies> | ||
|
||
</project> |
4 changes: 4 additions & 0 deletions
4
...ent/src/main/java/cn/iocoder/springboot/lab67/nettyclientdemo/NettyClientApplication.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
package cn.iocoder.springboot.lab67.nettyclientdemo; | ||
|
||
public class NettyClientApplication { | ||
} |
21 changes: 21 additions & 0 deletions
21
...t/src/main/java/cn/iocoder/springboot/lab67/nettyclientdemo/config/NettyClientConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package cn.iocoder.springboot.lab67.nettyclientdemo.config; | ||
|
||
import cn.iocoder.springboot.lab67.nettycommondemo.dispacher.MessageDispatcher; | ||
import cn.iocoder.springboot.lab67.nettycommondemo.dispacher.MessageHandlerContainer; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
|
||
@Configuration | ||
public class NettyClientConfig { | ||
|
||
@Bean | ||
public MessageDispatcher messageDispatcher() { | ||
return new MessageDispatcher(); | ||
} | ||
|
||
@Bean | ||
public MessageHandlerContainer messageHandlerContainer() { | ||
return new MessageHandlerContainer(); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
<?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"> | ||
<parent> | ||
<artifactId>lab-67-netty-demo</artifactId> | ||
<groupId>cn.iocoder.springboot.labs</groupId> | ||
<version>1.0-SNAPSHOT</version> | ||
</parent> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<artifactId>lab-67-netty-demo-common</artifactId> | ||
|
||
<properties> | ||
<!-- 插件相关配置 --> | ||
<maven.compiler.target>1.8</maven.compiler.target> | ||
<maven.compiler.source>1.8</maven.compiler.source> | ||
</properties> | ||
|
||
<dependencies> | ||
<!-- Netty 依赖 --> | ||
<dependency> | ||
<groupId>io.netty</groupId> | ||
<artifactId>netty-all</artifactId> | ||
<version>4.1.50.Final</version> | ||
</dependency> | ||
|
||
<!-- FastJSON 依赖 --> | ||
<dependency> | ||
<groupId>com.alibaba</groupId> | ||
<artifactId>fastjson</artifactId> | ||
<version>1.2.71</version> | ||
</dependency> | ||
|
||
<!-- 引入 Spring 相关依赖 --> | ||
<dependency> | ||
<groupId>org.springframework</groupId> | ||
<artifactId>spring-aop</artifactId> | ||
<version>5.2.5.RELEASE</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.springframework</groupId> | ||
<artifactId>spring-context</artifactId> | ||
<version>5.2.5.RELEASE</version> | ||
</dependency> | ||
|
||
<!-- 引入 SLF4J 依赖 --> | ||
<dependency> | ||
<groupId>org.slf4j</groupId> | ||
<artifactId>slf4j-api</artifactId> | ||
<version>1.7.30</version> | ||
</dependency> | ||
</dependencies> | ||
|
||
</project> |
41 changes: 41 additions & 0 deletions
41
...mo-common/src/main/java/cn/iocoder/springboot/lab67/nettycommondemo/codec/Invocation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package cn.iocoder.springboot.lab67.nettycommondemo.codec; | ||
|
||
public class Invocation { | ||
|
||
/** | ||
* 类型 - 心跳请求 | ||
*/ | ||
public static final String TYPE_HEARTBEAT_REQUEST = "HEARTBEAT_REQUEST"; | ||
/** | ||
* 类型 - 心跳响应 | ||
*/ | ||
public static final String TYPE_HEARTBEAT_RESPONSE = "HEARTBEAT_RESPONSE"; | ||
|
||
/** | ||
* 类型 | ||
*/ | ||
private String type; | ||
/** | ||
* 消息 | ||
*/ | ||
private String message; | ||
|
||
public String getType() { | ||
return type; | ||
} | ||
|
||
public Invocation setType(String type) { | ||
this.type = type; | ||
return this; | ||
} | ||
|
||
public String getMessage() { | ||
return message; | ||
} | ||
|
||
public Invocation setMessage(String message) { | ||
this.message = message; | ||
return this; | ||
} | ||
|
||
} |
39 changes: 39 additions & 0 deletions
39
...on/src/main/java/cn/iocoder/springboot/lab67/nettycommondemo/codec/InvocationDecoder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package cn.iocoder.springboot.lab67.nettycommondemo.codec; | ||
|
||
import com.alibaba.fastjson.JSON; | ||
import io.netty.buffer.ByteBuf; | ||
import io.netty.channel.ChannelHandlerContext; | ||
import io.netty.handler.codec.ByteToMessageDecoder; | ||
import io.netty.handler.codec.CorruptedFrameException; | ||
|
||
import java.util.List; | ||
|
||
public class InvocationDecoder extends ByteToMessageDecoder { | ||
|
||
@Override | ||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) { | ||
// 标记当前读取位置 | ||
in.markReaderIndex(); | ||
// 判断是否能够读取 length 长度 | ||
if (in.readableBytes() <= 4) { | ||
return; | ||
} | ||
// 读取长度 | ||
int length = in.readInt(); | ||
if (length < 0) { | ||
throw new CorruptedFrameException("negative length: " + length); | ||
} | ||
// 如果 message 不够可读,则退回到原读取位置 | ||
if (in.readableBytes() < length) { | ||
in.resetReaderIndex(); | ||
return; | ||
} | ||
// 读取内容 | ||
ByteBuf byteBuf = in.readRetainedSlice(length); | ||
// 解析成 Invocation | ||
byte[] content = byteBuf.array(); | ||
Invocation invocation = JSON.parseObject(content, Invocation.class); | ||
out.add(invocation); | ||
} | ||
|
||
} |
20 changes: 20 additions & 0 deletions
20
...on/src/main/java/cn/iocoder/springboot/lab67/nettycommondemo/codec/InvocationEncoder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package cn.iocoder.springboot.lab67.nettycommondemo.codec; | ||
|
||
import com.alibaba.fastjson.JSON; | ||
import io.netty.buffer.ByteBuf; | ||
import io.netty.channel.ChannelHandlerContext; | ||
import io.netty.handler.codec.MessageToByteEncoder; | ||
|
||
public class InvocationEncoder extends MessageToByteEncoder<Invocation> { | ||
|
||
@Override | ||
protected void encode(ChannelHandlerContext ctx, Invocation invocation, ByteBuf out) { | ||
// 将 Invocation 转换成 byte[] 数组 | ||
byte[] content = JSON.toJSONBytes(invocation); | ||
// 写入 length | ||
out.writeInt(content.length); | ||
// 写入内容 | ||
out.writeBytes(content); | ||
} | ||
|
||
} |
4 changes: 4 additions & 0 deletions
4
...o-common/src/main/java/cn/iocoder/springboot/lab67/nettycommondemo/dispacher/Message.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
package cn.iocoder.springboot.lab67.nettycommondemo.dispacher; | ||
|
||
public interface Message { | ||
} |
28 changes: 28 additions & 0 deletions
28
...rc/main/java/cn/iocoder/springboot/lab67/nettycommondemo/dispacher/MessageDispatcher.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package cn.iocoder.springboot.lab67.nettycommondemo.dispacher; | ||
|
||
import cn.iocoder.springboot.lab67.nettycommondemo.codec.Invocation; | ||
import com.alibaba.fastjson.JSON; | ||
import io.netty.channel.ChannelHandler; | ||
import io.netty.channel.ChannelHandlerContext; | ||
import io.netty.channel.SimpleChannelInboundHandler; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
|
||
@ChannelHandler.Sharable | ||
public class MessageDispatcher extends SimpleChannelInboundHandler<Invocation> { | ||
|
||
@Autowired | ||
private MessageHandlerContainer messageHandlerContainer; | ||
|
||
@Override | ||
protected void channelRead0(ChannelHandlerContext ctx, Invocation invocation) { | ||
// 获得 type 对应的 MessageHandler 处理器 | ||
MessageHandler messageHandler = messageHandlerContainer.getMessageHandler(invocation.getType()); | ||
// 解析消息 | ||
Class<? extends Message> messageClass = MessageHandlerContainer.getMessageClass(messageHandler); | ||
Message message = JSON.parseObject(invocation.getMessage(), messageClass); | ||
// 执行逻辑 | ||
// noinspection unchecked | ||
messageHandler.execute(ctx.channel(), message); | ||
} | ||
|
||
} |
20 changes: 20 additions & 0 deletions
20
...n/src/main/java/cn/iocoder/springboot/lab67/nettycommondemo/dispacher/MessageHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package cn.iocoder.springboot.lab67.nettycommondemo.dispacher; | ||
|
||
import io.netty.channel.Channel; | ||
|
||
public interface MessageHandler<T extends Message> { | ||
|
||
/** | ||
* 执行处理消息 | ||
* | ||
* @param channel 通道 | ||
* @param message 消息 | ||
*/ | ||
void execute(Channel channel, T message); | ||
|
||
/** | ||
* @return 消息类型,即每个 Message 实现类上的 TYPE 静态字段 | ||
*/ | ||
String getType(); | ||
|
||
} |
76 changes: 76 additions & 0 deletions
76
...n/java/cn/iocoder/springboot/lab67/nettycommondemo/dispacher/MessageHandlerContainer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package cn.iocoder.springboot.lab67.nettycommondemo.dispacher; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.aop.framework.AopProxyUtils; | ||
import org.springframework.beans.factory.InitializingBean; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.context.ApplicationContext; | ||
|
||
import java.lang.reflect.ParameterizedType; | ||
import java.lang.reflect.Type; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
|
||
public class MessageHandlerContainer implements InitializingBean { | ||
|
||
private Logger logger = LoggerFactory.getLogger(getClass()); | ||
|
||
/** | ||
* 消息类型与 MessageHandler 的映射 | ||
*/ | ||
private final Map<String, MessageHandler> handlers = new HashMap<>(); | ||
|
||
@Autowired | ||
private ApplicationContext applicationContext; | ||
|
||
@Override | ||
public void afterPropertiesSet() throws Exception { | ||
// 通过 ApplicationContext 获得所有 MessageHandler Bean | ||
applicationContext.getBeansOfType(MessageHandler.class).values() // 获得所有 MessageHandler Bean | ||
.forEach(messageHandler -> handlers.put(messageHandler.getType(), messageHandler)); // 添加到 handlers 中 | ||
logger.info("[afterPropertiesSet][消息处理器数量:{}]", handlers.size()); | ||
} | ||
|
||
protected MessageHandler getMessageHandler(String type) { | ||
MessageHandler handler = handlers.get(type); | ||
if (handler == null) { | ||
throw new IllegalArgumentException(String.format("类型(%s) 找不到匹配的 MessageHandler 处理器", type)); | ||
} | ||
return handler; | ||
} | ||
|
||
public static Class<? extends Message> getMessageClass(MessageHandler handler) { | ||
// 获得 Bean 对应的 Class 类名。因为有可能被 AOP 代理过。 | ||
Class<?> targetClass = AopProxyUtils.ultimateTargetClass(handler); | ||
// 获得接口的 Type 数组 | ||
Type[] interfaces = targetClass.getGenericInterfaces(); | ||
Class<?> superclass = targetClass.getSuperclass(); | ||
while ((Objects.isNull(interfaces) || 0 == interfaces.length) && Objects.nonNull(superclass)) { // 此处,是以父类的接口为准 | ||
interfaces = superclass.getGenericInterfaces(); | ||
superclass = targetClass.getSuperclass(); | ||
} | ||
if (Objects.nonNull(interfaces)) { | ||
// 遍历 interfaces 数组 | ||
for (Type type : interfaces) { | ||
// 要求 type 是泛型参数 | ||
if (type instanceof ParameterizedType) { | ||
ParameterizedType parameterizedType = (ParameterizedType) type; | ||
// 要求是 MessageHandler 接口 | ||
if (Objects.equals(parameterizedType.getRawType(), MessageHandler.class)) { | ||
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); | ||
// 取首个元素 | ||
if (Objects.nonNull(actualTypeArguments) && actualTypeArguments.length > 0) { | ||
return (Class<Message>) actualTypeArguments[0]; | ||
} else { | ||
throw new IllegalStateException(String.format("类型(%s) 获得不到消息类型", handler)); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
throw new IllegalStateException(String.format("类型(%s) 获得不到消息类型", handler)); | ||
} | ||
|
||
} |
Oops, something went wrong.