code-learning/netty/50-Netty 源码解析-ChannelHandler(三)之 SimpleChannelInboundHandler.md

291 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 精尽 Netty 源码解析 —— ChannelHandler之 SimpleChannelInboundHandler
# 1. 概述
在本文,我们来分享 SimpleChannelInboundHandler 处理器。考虑到 Simple**UserEvent**ChannelHandler 和 SimpleChannelInboundHandler 的实现基本一致,所以也会在本文中分享。
如果胖友对 SimpleChannelInboundHandler 的使用不了解,请先看下 [《一起学Netty之 SimpleChannelInboundHandler》](https://blog.csdn.net/linuu/article/details/51307060) ,嘿嘿。
# 2. SimpleChannelInboundHandler
`io.netty.channel.SimpleChannelInboundHandler` ,继承 ChannelInboundHandlerAdapter 类,抽象类,处理**指定类型**的消息。应用程序中,我们可以实现 SimpleChannelInboundHandler 后,实现对**指定类型**的消息的自定义处理。
## 2.1 构造方法
```
public abstract class SimpleChannelInboundHandler<I> extends ChannelInboundHandlerAdapter {
/**
* 类型匹配器
*/
private final TypeParameterMatcher matcher;
/**
* 使用完消息,是否自动释放
*
* @see #channelRead(ChannelHandlerContext, Object)
*/
private final boolean autoRelease;
/**
* see {@link #SimpleChannelInboundHandler(boolean)} with {@code true} as boolean parameter.
*/
protected SimpleChannelInboundHandler() {
this(true);
}
/**
* Create a new instance which will try to detect the types to match out of the type parameter of the class.
*
* @param autoRelease {@code true} if handled messages should be released automatically by passing them to
* {@link ReferenceCountUtil#release(Object)}.
*/
protected SimpleChannelInboundHandler(boolean autoRelease) {
// <1> 获得 matcher
matcher = TypeParameterMatcher.find(this, SimpleChannelInboundHandler.class, "I");
this.autoRelease = autoRelease;
}
/**
* see {@link #SimpleChannelInboundHandler(Class, boolean)} with {@code true} as boolean value.
*/
protected SimpleChannelInboundHandler(Class<? extends I> inboundMessageType) {
this(inboundMessageType, true);
}
/**
* Create a new instance
*
* @param inboundMessageType The type of messages to match
* @param autoRelease {@code true} if handled messages should be released automatically by passing them to
* {@link ReferenceCountUtil#release(Object)}.
*/
protected SimpleChannelInboundHandler(Class<? extends I> inboundMessageType, boolean autoRelease) {
// <2> 获得 matcher
matcher = TypeParameterMatcher.get(inboundMessageType);
this.autoRelease = autoRelease;
}
// ... 省略其它方法
}
```
- ```
matcher
```
属性,有
两种
方式赋值。
- 【常用】`<1>` 处,使用类的 `I` 泛型对应的 TypeParameterMatcher 类型匹配器。
- `<2>` 处,使用 `inboundMessageType` 参数对应的 TypeParameterMatcher 类型匹配器。
- 在大多数情况下,我们不太需要特别详细的了解 `io.netty.util.internal.TypeParameterMatcher` 的代码实现,感兴趣的胖友可以自己看看 [《netty 简单Inbound通道处理器SimpleChannelInboundHandler》](http://donald-draper.iteye.com/blog/2387772) 的 [「TypeParameterMatcher」](https://svip.iocoder.cn/Netty/ChannelHandler-3-SimpleChannelInboundHandler/#) 部分。
- `autoRelease` 属性,使用完消息,是否自动释放。
## 2.2 acceptInboundMessage
`#acceptInboundMessage(Object msg)` 方法,判断消息是否匹配。代码如下:
```
/**
* Returns {@code true} if the given message should be handled. If {@code false} it will be passed to the next
* {@link ChannelInboundHandler} in the {@link ChannelPipeline}.
*/
public boolean acceptInboundMessage(Object msg) {
return matcher.match(msg);
}
```
一般情况下,`matcher` 的类型是 ReflectiveMatcher( 它是 TypeParameterMatcher 的内部类 )。代码如下:
```
private static final class ReflectiveMatcher extends TypeParameterMatcher {
/**
* 类型
*/
private final Class<?> type;
ReflectiveMatcher(Class<?> type) {
this.type = type;
}
@Override
public boolean match(Object msg) {
return type.isInstance(msg); // <1>
}
}
```
- 匹配逻辑,看 `<1>` 处,使用 `Class#isInstance(Object obj)` 方法。对于这个方法,如果我们定义的 `I` 泛型是个父类,那可以匹配所有的子类。例如 `I` 设置为 Object 类,那么所有消息,都可以被匹配列。
## 2.3 channelRead
```
1: @Override
2: public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
3: // 是否要释放消息
4: boolean release = true;
5: try {
6: // 判断是否为匹配的消息
7: if (acceptInboundMessage(msg)) {
8: @SuppressWarnings("unchecked")
9: I imsg = (I) msg;
10: // 处理消息
11: channelRead0(ctx, imsg);
12: } else {
13: // 不需要释放消息
14: release = false;
15: // 触发 Channel Read 到下一个节点
16: ctx.fireChannelRead(msg);
17: }
18: } finally {
19: // 判断,是否要释放消息
20: if (autoRelease && release) {
21: ReferenceCountUtil.release(msg);
22: }
23: }
24: }
```
- 第 4 行:`release` 属性,是否需要释放消息。
- 第 7 行:调用 `#acceptInboundMessage(Object msg)` 方法,判断是否为匹配的消息。
- ① **匹配**,调用 `#channelRead0(ChannelHandlerContext ctx, I msg)` **抽象**方法,处理消息。代码如下:
```
/**
* <strong>Please keep in mind that this method will be renamed to
* {@code messageReceived(ChannelHandlerContext, I)} in 5.0.</strong>
*
* Is called for each message of type {@link I}.
*
* @param ctx the {@link ChannelHandlerContext} which this {@link SimpleChannelInboundHandler}
* belongs to
* @param msg the message to handle
* @throws Exception is thrown if an error occurred
*/
protected abstract void channelRead0(ChannelHandlerContext ctx, I msg) throws Exception;
```
- 子类实现 SimpleChannelInboundHandler 类后,实现该方法,就能很方便的处理消息。
- ② **不匹配**,标记不需要释放消息,并触发 Channel Read 到**下一个节点**。
- 第 18 至 23 行:通过 `release` 变量 + `autoRelease` 属性,判断是否需要释放消息。若需要,调用 `ReferenceCountUtil#release(Object msg)` 方法,释放消息。😈 还是蛮方便的。
# 3. SimpleUserEventChannelHandler
`io.netty.channel.SimpleUserEventChannelHandler` ,继承 ChannelInboundHandlerAdapter 类,抽象类,处理**指定事件**的消息。
SimpleUserEventChannelHandler 和 SimpleChannelInboundHandler 基本一致,差别在于将指定类型的消息,改成了制定类型的事件。😈 所以,笔者就不详细解析了。
代码如下:
```
public abstract class SimpleUserEventChannelHandler<I> extends ChannelInboundHandlerAdapter {
/**
* 类型匹配器
*/
private final TypeParameterMatcher matcher;
/**
* 使用完消息,是否自动释放
*
* @see #channelRead(ChannelHandlerContext, Object)
*/
private final boolean autoRelease;
/**
* see {@link #SimpleUserEventChannelHandler(boolean)} with {@code true} as boolean parameter.
*/
protected SimpleUserEventChannelHandler() {
this(true);
}
/**
* Create a new instance which will try to detect the types to match out of the type parameter of the class.
*
* @param autoRelease {@code true} if handled events should be released automatically by passing them to
* {@link ReferenceCountUtil#release(Object)}.
*/
protected SimpleUserEventChannelHandler(boolean autoRelease) {
matcher = TypeParameterMatcher.find(this, SimpleUserEventChannelHandler.class, "I");
this.autoRelease = autoRelease;
}
/**
* see {@link #SimpleUserEventChannelHandler(Class, boolean)} with {@code true} as boolean value.
*/
protected SimpleUserEventChannelHandler(Class<? extends I> eventType) {
this(eventType, true);
}
/**
* Create a new instance
*
* @param eventType The type of events to match
* @param autoRelease {@code true} if handled events should be released automatically by passing them to
* {@link ReferenceCountUtil#release(Object)}.
*/
protected SimpleUserEventChannelHandler(Class<? extends I> eventType, boolean autoRelease) {
matcher = TypeParameterMatcher.get(eventType);
this.autoRelease = autoRelease;
}
/**
* Returns {@code true} if the given user event should be handled. If {@code false} it will be passed to the next
* {@link ChannelInboundHandler} in the {@link ChannelPipeline}.
*/
protected boolean acceptEvent(Object evt) throws Exception {
return matcher.match(evt);
}
@Override
public final void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
// 是否要释放消息
boolean release = true;
try {
// 判断是否为匹配的消息
if (acceptEvent(evt)) {
@SuppressWarnings("unchecked")
I ievt = (I) evt;
// 处理消息
eventReceived(ctx, ievt);
} else {
// 不需要释放消息
release = false;
// 触发 Channel Read 到下一个节点
ctx.fireUserEventTriggered(evt);
}
} finally {
// 判断,是否要释放消息
if (autoRelease && release) {
ReferenceCountUtil.release(evt);
}
}
}
/**
* Is called for each user event triggered of type {@link I}.
*
* @param ctx the {@link ChannelHandlerContext} which this {@link SimpleUserEventChannelHandler} belongs to
* @param evt the user event to handle
*
* @throws Exception is thrown if an error occurred
*/
protected abstract void eventReceived(ChannelHandlerContext ctx, I evt) throws Exception;
}
```
# 666. 彩蛋
木有彩蛋hoho 。