- 浏览: 980992 次
文章分类
- 全部博客 (428)
- Hadoop (2)
- HBase (1)
- ELK (1)
- ActiveMQ (13)
- Kafka (5)
- Redis (14)
- Dubbo (1)
- Memcached (5)
- Netty (56)
- Mina (34)
- NIO (51)
- JUC (53)
- Spring (13)
- Mybatis (17)
- MySQL (21)
- JDBC (12)
- C3P0 (5)
- Tomcat (13)
- SLF4J-log4j (9)
- P6Spy (4)
- Quartz (12)
- Zabbix (7)
- JAVA (9)
- Linux (15)
- HTML (9)
- Lucene (0)
- JS (2)
- WebService (1)
- Maven (4)
- Oracle&MSSQL (14)
- iText (11)
- Development Tools (8)
- UTILS (4)
- LIFE (8)
最新评论
-
Donald_Draper:
Donald_Draper 写道刘落落cici 写道能给我发一 ...
DatagramChannelImpl 解析三(多播) -
Donald_Draper:
刘落落cici 写道能给我发一份这个类的源码吗Datagram ...
DatagramChannelImpl 解析三(多播) -
lyfyouyun:
请问楼主,执行消息发送的时候,报错:Transport sch ...
ActiveMQ连接工厂、连接详解 -
ezlhq:
关于 PollArrayWrapper 状态含义猜测:参考 S ...
WindowsSelectorImpl解析一(FdMap,PollArrayWrapper) -
flyfeifei66:
打算使用xmemcache作为memcache的客户端,由于x ...
Memcached分布式客户端(Xmemcached)
Netty 通道处理器ChannelHandler和适配器定义ChannelHandlerAdapter:
http://donald-draper.iteye.com/blog/2386891
Netty Inbound/Outbound通道处理器定义:http://donald-draper.iteye.com/blog/2387019
引言:
前面一篇文章我们看了Inbound/Outbound通道处理器定义先来回顾一下先:
通道Inbound处理器,主要是处理从peer发送过来的字节流;通道处理器上下文关联的通道注册到事件循环EventLoop时,触发channelRegistered方法;通道处理器上下文关联的通道激活时,触发channelActive方法;通道从peer读取消息时,触发channelRead方法;当上一消息通过#channelRead方法,并被当先读操作消费时,触发channelReadComplete方法,如果通道配置项
#AUTO_READ为关闭状态,没有进一步尝试从当前通道读取inbound数据时,直到ChannelHandlerContext#read调用,触发;当用户事件发生时,触发userEventTriggered方法;异常抛出时,触发exceptionCaught方法;当通道可写状态改变时,触发channelWritabilityChanged方法;通道处理器上下文关联的通道注册到事件循环EventLoop,但处于非激活状态,达到生命周期的末端时,触发channelInactive方法;通道处理器上下文关联的通道从事件循环EventLoop移除时,触发channelUnregistered方法。
Inbound通道handler适配器ChannelInboundHandlerAdapter,提供的Inbound通道处理器的所有方法的实现,但实现仅仅是,转发操作给Channel管道线的下一个通道处理器,子类必须重写方法。需要注意的是,在#channelRead方法自动返回后,消息并没有释放。如果你寻找ChannelInboundHandler的实现,可以自动释放接受的到消息可以使用SimpleChannelInboundHandler。
Outbound通道处理器ChannelOutboundHandler主要处理outbound IO操作。当绑定操作发生时,调用bind方法;当连接操作发生时,调用connect方法;read方法拦截通道处理器上下文读操作;当写操发生时,调用write方法,写操作通过Channel管道线写消息,当通道调用#flush方法时,消息将会被刷新,发送出去;当一个刷新操作发生时,调用flush方法,刷新操作将会刷新所有先前已经写,待发送的消息。
Outbound通道Handler适配器ChannelOutboundHandlerAdapter为Outbound通道处理器的基本实现,这个实现仅仅通过通道处理器上下文转发方法的调用。
子类必须重写Outbound通道Handler适配器的相关方法。
在Mina中,通道读写全部在一个通道Handler,Mina提供的通道Handler适配器,我们在使用通道处理器时继承它,实现我们需要关注的读写事件。而Netty使用InBound和OutBound将通道的读写分离,同时提供了InBound和OutBound通道Handler的适配器。
今天来看一下SimpleChannelInboundHandler:
来看读取消息对象方法:
其中有两点需要关注:
1.
//ChannelHandlerContext
//ChannelInboundInvoker
2.
//ReferenceCounted
从上面来看,读操作,首先判断跟定的消息类型是否可以被处理,如果是,则委托给channelRead0,如果返回false,则将消息转递给Channel管道线的下一个通道处理器;最后,如果autoRelease为自动释放消息,且消息已处理则释放消息。
在简单Inbound通道处理器的构造方法:
和acceptInboundMessage方法中
//判断跟定的消息类型是否可以被处理,如果返回false,则将消息转递给Channel管道线的下一个通道处理器
涉及到一个参数类型匹配器TypeParameterMatcher,为了理解TypeParameterMatcher花了几天时间,
学习了一下java Type体系结构,在往下看之前,需要了解java Type体系结构,具体可以参考一下连接:
Type —— Java类型:http://blog.csdn.net/a327369238/article/details/52621043
详解Java泛型type体系整理:http://developer.51cto.com/art/201103/250028.htm
黑马程序员--Java基础加强--13.利用反射操作泛型II【TypeVariable】【GenericArrayType】【WildcardType】【Type及其子接口的来历】【个人总结】
:http://blog.csdn.net/benjaminzhang666/article/details/9839007
泛型通配符extends与super的区别:http://www.cnblogs.com/yepei/p/6591289.html
另外附上java Type体系结构的示例地址:https://github.com/Donaldhan/java-base-demo
本身这篇文章应该上个星期就出来呢?由于对java Type体系结构不熟,难以理解参数类型匹配器TypeParameterMatcher,所以推迟到现在,本身同时想写一篇java Type体系结构相关的文章,后来一想算了,网上很多资料,再加上自己写Demo里面有相关的说明,就不写了,一个字懒......
言归正传,下面我们来看TypeParameterMatcher
这个类型参数匹配器就不说了,各种变量的叫法,容易搞混,要结合代码注释看。
简单小节一下:
类型参数匹配器,作用主要主要是判断实例的类型是否为类型参数匹配器对应类型的实例,是则返回ture,否返回false。主要是用于,当通道读取消息对象时,判断通道是不可以处理此消息对象。
get方法:根据Class类型获取类型参数匹配器,首先从Netty内部线程本地Map,获取当前线程类型参数匹配器缓存,从类型参数匹配器缓存,获取参数类型parameterType对应的类型参数匹配器,如果匹配器为空且匹配参数为Object,则匹配器为NOOP,否则,根据参数类型创建ReflectiveMatcher添加到缓存中。
find方法:跟实例object,类型父类parametrizedSuperclass,类型参数名typeParamName,
获取类型参数名object对应的类型参数匹配器,首先从Netty内部线程本地Map,获取当前线程类型参数匹配器缓存,从类型参数匹配器缓存,获取objec类型thisClass对应的类型参数匹配器映射关系,如果不存在object类型对应的类型参数匹配器映射关系,则创建,并添加到缓存中,否则,从object类型对应的类型参数匹配器Map中获取,对应的类型参数匹配器,如果object对应的类型参数匹配器为空,则从父类中获取类型参数名对应的类型的参数匹配器(find0方法获取类型参数名对应的原始类),并将类型与从父类中获取匹配器映射关系,添加到缓存中,否则直接返回匹配器。
find0方法:获取obejct实际类型父类parametrizedSuperclass泛型参数中,类型参数名为typeParamName对应的原始类型过程为,首先获取object的类型currentClass,如果当前类型currentClass的父类为parametrizedSuperclass,获取当前类父类的泛型类型变量,寻找类型参数名对应的类型变量,如果找到,则记录类型变量索引位置,如果索引为位置小于0,即,在object类型父类的类型变量中没有找到typeParamName对应的类型变量,否则,获取当前类的父类泛型类型,如果父类的泛型类型非参数化类型,则返回Object类型,否则,获取父类的实际类型参数,如果实际类型参数为参数化类型,则获取索引对应实际类型参数的原始类型RawType,
如果实际类型为Class,则直接返回Class,如果实际类型参数为泛型数组类型,获取泛型数组类型的泛型组件类型GenericComponentType,如果组件类型为参数化类型,则组件类型为原始类型RawType,如果组件类型为Class,则创建对应的数组实例,并获取实例的类型,如果实际类型参数为类型变量,转化实际类型参数为类型变量v,如果类型变量的声明类不是Class,则返回Object类型,否则设置参数化父类的类型为类型变量v的声明类,如果参数类型父类为thisClass类型,则跳出当前循环,否则返回Object类型,这时,当前类型currentClass的父类为parametrizedSuperclas的情况结束;如果父类不为parametrizedSuperclas,则获取currentClass父类,并设置为当前类继续自旋。自旋的目的是,找到与parametrizedSuperclas类型相等的object类型或父类型。
总结:
简单Inbound通道处理器SimpleChannelInboundHandler<I>,内部有连个变量一个为参数类型匹配器,用来判断通道是否可以处理消息,另一个变量autoRelease,用于控制是否在通道处理消息完毕时,释放消息。读取方法channelRead,首先判断跟定的消息类型是否可以被处理,如果是,则委托给channelRead0,channelRead0待子类实现;如果返回false,则将消息转递给Channel管道线的下一个通道处理器;最后,如果autoRelease为自动释放消息,且消息已处理则释放消息。
http://donald-draper.iteye.com/blog/2386891
Netty Inbound/Outbound通道处理器定义:http://donald-draper.iteye.com/blog/2387019
引言:
前面一篇文章我们看了Inbound/Outbound通道处理器定义先来回顾一下先:
通道Inbound处理器,主要是处理从peer发送过来的字节流;通道处理器上下文关联的通道注册到事件循环EventLoop时,触发channelRegistered方法;通道处理器上下文关联的通道激活时,触发channelActive方法;通道从peer读取消息时,触发channelRead方法;当上一消息通过#channelRead方法,并被当先读操作消费时,触发channelReadComplete方法,如果通道配置项
#AUTO_READ为关闭状态,没有进一步尝试从当前通道读取inbound数据时,直到ChannelHandlerContext#read调用,触发;当用户事件发生时,触发userEventTriggered方法;异常抛出时,触发exceptionCaught方法;当通道可写状态改变时,触发channelWritabilityChanged方法;通道处理器上下文关联的通道注册到事件循环EventLoop,但处于非激活状态,达到生命周期的末端时,触发channelInactive方法;通道处理器上下文关联的通道从事件循环EventLoop移除时,触发channelUnregistered方法。
Inbound通道handler适配器ChannelInboundHandlerAdapter,提供的Inbound通道处理器的所有方法的实现,但实现仅仅是,转发操作给Channel管道线的下一个通道处理器,子类必须重写方法。需要注意的是,在#channelRead方法自动返回后,消息并没有释放。如果你寻找ChannelInboundHandler的实现,可以自动释放接受的到消息可以使用SimpleChannelInboundHandler。
Outbound通道处理器ChannelOutboundHandler主要处理outbound IO操作。当绑定操作发生时,调用bind方法;当连接操作发生时,调用connect方法;read方法拦截通道处理器上下文读操作;当写操发生时,调用write方法,写操作通过Channel管道线写消息,当通道调用#flush方法时,消息将会被刷新,发送出去;当一个刷新操作发生时,调用flush方法,刷新操作将会刷新所有先前已经写,待发送的消息。
Outbound通道Handler适配器ChannelOutboundHandlerAdapter为Outbound通道处理器的基本实现,这个实现仅仅通过通道处理器上下文转发方法的调用。
子类必须重写Outbound通道Handler适配器的相关方法。
在Mina中,通道读写全部在一个通道Handler,Mina提供的通道Handler适配器,我们在使用通道处理器时继承它,实现我们需要关注的读写事件。而Netty使用InBound和OutBound将通道的读写分离,同时提供了InBound和OutBound通道Handler的适配器。
今天来看一下SimpleChannelInboundHandler:
package io.netty.channel; import io.netty.util.ReferenceCountUtil; import io.netty.util.internal.TypeParameterMatcher; /** * {@link ChannelInboundHandlerAdapter} which allows to explicit only handle a specific type of messages. *简单Inbound通道处理器SimpleChannelInboundHandler,允许明确处理一种特殊类型的消息。 * For example here is an implementation which only handle {@link String} messages. *下面是一个处理String类型数据Inbound通道处理器实现 * <pre> * public class StringHandler extends * {@link SimpleChannelInboundHandler}<{@link String}> { * * {@code @Override} * protected void channelRead0({@link ChannelHandlerContext} ctx, {@link String} message) * throws {@link Exception} { * System.out.println(message); * } * } * </pre> * * Be aware that depending of the constructor parameters it will release all handled messages by passing them to * {@link ReferenceCountUtil#release(Object)}. In this case you may need to use * {@link ReferenceCountUtil#retain(Object)} if you pass the object to the next handler in the {@link ChannelPipeline}. *需要注意的是,是否通过转递消息给ReferenceCountUtil#release方法,释放处理过的消息,依赖于构造参数autoRelease(boolean)。 如果你需要将消息传递给Channle管道线的下一个通道处理器,你需要调用ReferenceCountUtil#retain(Object)方法; * <h3>Forward compatibility notice</h3> * 转发兼容性提醒 * Please keep in mind that {@link #channelRead0(ChannelHandlerContext, I)} will be renamed to * {@code messageReceived(ChannelHandlerContext, I)} in 5.0. * 请注意:#channelRead0方法在Netty5,中将被命名为消息messageReceived。 */ public abstract class SimpleChannelInboundHandler<I> extends ChannelInboundHandlerAdapter { private final TypeParameterMatcher matcher;//类型参数匹配器 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. *创建一个实例,尝试探测接受消息类型与SimpleChannelInboundHandler的I的类型是否相同。 * @param autoRelease {@code true} if handled messages should be released automatically by passing them to * {@link ReferenceCountUtil#release(Object)}. 是否通过ReferenceCountUtil#release方法释放消息 */ protected SimpleChannelInboundHandler(boolean autoRelease) { 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) { matcher = TypeParameterMatcher.get(inboundMessageType); this.autoRelease = autoRelease; } /** * 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}. 判断跟定的消息类型是否可以被处理,如果返回false,则将消息转递给Channel管道线的下一个通道处理器 */ public boolean acceptInboundMessage(Object msg) throws Exception { return matcher.match(msg); } //读取消息对象 @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { boolean release = true; try { if (acceptInboundMessage(msg)) { @SuppressWarnings("unchecked") I imsg = (I) msg; //如果消息属于本Handler可以处理的消息类型,则委托给channelRead0 channelRead0(ctx, imsg); } else { release = false; //当前通道Handler,不可处理消息,通过通道上下文,通知管道线中的下一个通道处理器,接受到一个消息 ctx.fireChannelRead(msg); } } finally { if (autoRelease && release) { //如果autoRelease为自动释放消息,且消息已处理则释放消息 ReferenceCountUtil.release(msg); } } } /** * [b]Please keep in mind that this method will be renamed to * {@code messageReceived(ChannelHandlerContext, I)} in 5.0.[/b] *注意此方法在5.0以后将命名为messageReceived * 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; }
来看读取消息对象方法:
//读取消息对象 @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { boolean release = true; try { if (acceptInboundMessage(msg)) { @SuppressWarnings("unchecked") I imsg = (I) msg; //如果消息属于本Handler可以处理的消息类型,则委托给channelRead0 channelRead0(ctx, imsg); } else { release = false; //当前通道Handler,不可处理消息,通过通道上下文,通知管道线中的下一个通道处理器,接受到一个消息 ctx.fireChannelRead(msg); } } finally { if (autoRelease && release) { //如果autoRelease为自动释放消息,且消息已处理则释放消息 ReferenceCountUtil.release(msg); } } }
其中有两点需要关注:
1.
//当前通道Handler,不可处理消息,通过通道上下文,通知管道线中的下一个通道处理器,接受到一个消息 ctx.fireChannelRead(msg);
//ChannelHandlerContext
public interface ChannelHandlerContext extends AttributeMap, ChannelInboundInvoker, ChannelOutboundInvoker { @Override ChannelHandlerContext fireChannelRead(Object msg); }
//ChannelInboundInvoker
/** * A {@link Channel} received a message. *通道接收一个消息 * This will result in having the {@link ChannelInboundHandler#channelRead(ChannelHandlerContext, Object)} * method called of the next {@link ChannelInboundHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. ChannelInboundHandler#channelRead方法调用将会通知,通道所在的Channel管道线中的下一个通道处理器,接受一个消息 */ ChannelInboundInvoker fireChannelRead(Object msg);
2.
//如果autoRelease为自动释放消息,且消息已处理则释放消息 ReferenceCountUtil.release(msg);
//ReferenceCountUtil /** * Try to call {@link ReferenceCounted#release()} if the specified message implements {@link ReferenceCounted}. * If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing. 如果消息实现了ReferenceCounted,则调用ReferenceCounted#release(),如果不是什么都不做 */ public static boolean release(Object msg) { if (msg instanceof ReferenceCounted) { return ((ReferenceCounted) msg).release(); } return false; }
//ReferenceCounted
/** * Decreases the reference count by {@code 1} and deallocates this object if the reference count reaches at * {@code 0}. *自减引用计数器,如果计数器为0,则回收对象。 * @return {@code true} if and only if the reference count became {@code 0} and this object has been deallocated */ boolean release();
从上面来看,读操作,首先判断跟定的消息类型是否可以被处理,如果是,则委托给channelRead0,如果返回false,则将消息转递给Channel管道线的下一个通道处理器;最后,如果autoRelease为自动释放消息,且消息已处理则释放消息。
在简单Inbound通道处理器的构造方法:
protected SimpleChannelInboundHandler(boolean autoRelease) { matcher = TypeParameterMatcher.find(this, SimpleChannelInboundHandler.class, "I"); this.autoRelease = autoRelease; } protected SimpleChannelInboundHandler(Class<? extends I> inboundMessageType, boolean autoRelease) { matcher = TypeParameterMatcher.get(inboundMessageType); this.autoRelease = autoRelease; }
和acceptInboundMessage方法中
//判断跟定的消息类型是否可以被处理,如果返回false,则将消息转递给Channel管道线的下一个通道处理器
public boolean acceptInboundMessage(Object msg) throws Exception { return matcher.match(msg); }
涉及到一个参数类型匹配器TypeParameterMatcher,为了理解TypeParameterMatcher花了几天时间,
学习了一下java Type体系结构,在往下看之前,需要了解java Type体系结构,具体可以参考一下连接:
Type —— Java类型:http://blog.csdn.net/a327369238/article/details/52621043
详解Java泛型type体系整理:http://developer.51cto.com/art/201103/250028.htm
黑马程序员--Java基础加强--13.利用反射操作泛型II【TypeVariable】【GenericArrayType】【WildcardType】【Type及其子接口的来历】【个人总结】
:http://blog.csdn.net/benjaminzhang666/article/details/9839007
泛型通配符extends与super的区别:http://www.cnblogs.com/yepei/p/6591289.html
另外附上java Type体系结构的示例地址:https://github.com/Donaldhan/java-base-demo
本身这篇文章应该上个星期就出来呢?由于对java Type体系结构不熟,难以理解参数类型匹配器TypeParameterMatcher,所以推迟到现在,本身同时想写一篇java Type体系结构相关的文章,后来一想算了,网上很多资料,再加上自己写Demo里面有相关的说明,就不写了,一个字懒......
言归正传,下面我们来看TypeParameterMatcher
package io.netty.util.internal; import java.lang.reflect.Array; import java.lang.reflect.GenericArrayType; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.util.HashMap; import java.util.Map; public abstract class TypeParameterMatcher { //默认空参数类型匹配器,匹配方法永远返回true private static final TypeParameterMatcher NOOP = new TypeParameterMatcher() { @Override public boolean match(Object msg) { return true; } }; //判断消息对象类型是否匹配当前类型匹配器 public abstract boolean match(Object msg); //反射匹配器 private static final class ReflectiveMatcher extends TypeParameterMatcher { private final Class<?> type; ReflectiveMatcher(Class<?> type) { this.type = type; } //根据对象是为类型Type的实例,来判断是否消息是否匹配 @Override public boolean match(Object msg) { return type.isInstance(msg); } } TypeParameterMatcher() { } //根据Class类型获取类型参数匹配器 public static TypeParameterMatcher get(final Class<?> parameterType) { //从Netty内部线程本地Map,获取当前线程类型参数匹配器缓存 final Map<Class<?>, TypeParameterMatcher> getCache = InternalThreadLocalMap.get().typeParameterMatcherGetCache(); //从类型参数匹配器缓存,获取类型parameterType对应的类型参数匹配器 TypeParameterMatcher matcher = getCache.get(parameterType); if (matcher == null) {//如果匹配器为空 if (parameterType == Object.class) {匹配参数为Object,匹配器为NOOP matcher = NOOP; } else { matcher = new ReflectiveMatcher(parameterType); } getCache.put(parameterType, matcher); } return matcher; } //跟实例object,类型父类parametrizedSuperclass,类型参数名typeParamName,获取类型参数名object对应的类型参数匹配器 public static TypeParameterMatcher find( final Object object, final Class<?> parametrizedSuperclass, final String typeParamName) { //从Netty内部线程本地Map,获取当前线程类型参数匹配器缓存 final Map<Class<?>, Map<String, TypeParameterMatcher>> findCache = InternalThreadLocalMap.get().typeParameterMatcherFindCache(); //获取object类型 final Class<?> thisClass = object.getClass(); //从类型参数匹配器缓存,获取类型thisClass对应的类型参数匹配器映射关系 Map<String, TypeParameterMatcher> map = findCache.get(thisClass); if (map == null) { //如果不存在object类型对应的类型参数匹配器映射关系,则创建,并添加到缓存中 map = new HashMap<String, TypeParameterMatcher>(); findCache.put(thisClass, map); } //从object类型对应的类型参数匹配器Map中获取,对应的类型参数匹配器 TypeParameterMatcher matcher = map.get(typeParamName); if (matcher == null) { //如果object对应的类型参数匹配器为空,则从父类中获取类型参数名对应的类型的参数匹配器 matcher = get(find0(object, parametrizedSuperclass, typeParamName)); //类型参数名和类型参数匹配器,添加到对应的映射Map中 map.put(typeParamName, matcher); } return matcher; } //获取obejct实际类型父类parametrizedSuperclass泛型参数中,类型参数名为typeParamName对应的原始类型 private static Class<?> find0( final Object object, Class<?> parametrizedSuperclass, String typeParamName) { //获取object的类型 final Class<?> thisClass = object.getClass(); Class<?> currentClass = thisClass; for (;;) { if (currentClass.getSuperclass() == parametrizedSuperclass) {//如果当前类型父类为parametrizedSuperclass int typeParamIndex = -1; //获取当前类父类的泛型类型变量 TypeVariable<?>[] typeParams = currentClass.getSuperclass().getTypeParameters(); for (int i = 0; i < typeParams.length; i ++) { //寻找类型参数名对应的类型变量,如果找到,则记录类型变量索引位置 if (typeParamName.equals(typeParams[i].getName())) { typeParamIndex = i; break; } } //如果索引为位置小于0,即,在object类型父类的类型变量中没有找到typeParamName对应的类型变量 if (typeParamIndex < 0) { throw new IllegalStateException( "unknown type parameter '" + typeParamName + "': " + parametrizedSuperclass); } //获取当前类的父类泛型类型 Type genericSuperType = currentClass.getGenericSuperclass(); if (!(genericSuperType instanceof ParameterizedType)) { //如果父类的泛型类型非参数化类型,则返回Object类型 return Object.class; } //获取父类的实际类型参数 Type[] actualTypeParams = ((ParameterizedType) genericSuperType).getActualTypeArguments(); Type actualTypeParam = actualTypeParams[typeParamIndex]; if (actualTypeParam instanceof ParameterizedType) { //如果实际类型参数为参数化类型,则获取实际类型参数的原始类型RawType(不包括泛型部分) actualTypeParam = ((ParameterizedType) actualTypeParam).getRawType(); } if (actualTypeParam instanceof Class) { //如果实际类型为Class,则直接返回Class return (Class<?>) actualTypeParam; } if (actualTypeParam instanceof GenericArrayType) { //如果实际类型参数为泛型数组类型,获取泛型数组类型的泛型组件类型GenericComponentType Type componentType = ((GenericArrayType) actualTypeParam).getGenericComponentType(); if (componentType instanceof ParameterizedType) { 如果组件类型为参数化类型,则组件类型为原始类型RawType componentType = ((ParameterizedType) componentType).getRawType(); } if (componentType instanceof Class) { //如果组件类型为Class,则创建对应的数组实例,并获取实例的类型 return Array.newInstance((Class<?>) componentType, 0).getClass(); } } if (actualTypeParam instanceof TypeVariable) { //如果实际类型参数为类型变量,转化实际类型参数为类型变量 // Resolved type parameter points to another type parameter. TypeVariable<?> v = (TypeVariable<?>) actualTypeParam; currentClass = thisClass; if (!(v.getGenericDeclaration() instanceof Class)) { //如果类型变量的声明类不是Class,则返回Object类型 return Object.class; } //参数化父类的类型为,类型变量v的声明类 parametrizedSuperclass = (Class<?>) v.getGenericDeclaration(); //获取类型变量名称 typeParamName = v.getName(); if (parametrizedSuperclass.isAssignableFrom(thisClass)) { //如果参数类型父类为thisClass类型,则跳出当前循环 continue; } else { //否则返回Object类型 return Object.class; } } return fail(thisClass, typeParamName); } //否则获取当前类型的父类 currentClass = currentClass.getSuperclass(); if (currentClass == null) { return fail(thisClass, typeParamName); } } } //找不到类型参数名对应的类型,则抛出非法状态异常 private static Class<?> fail(Class<?> type, String typeParamName) { throw new IllegalStateException( "cannot determine the type of the type parameter '" + typeParamName + "': " + type); } }
这个类型参数匹配器就不说了,各种变量的叫法,容易搞混,要结合代码注释看。
简单小节一下:
类型参数匹配器,作用主要主要是判断实例的类型是否为类型参数匹配器对应类型的实例,是则返回ture,否返回false。主要是用于,当通道读取消息对象时,判断通道是不可以处理此消息对象。
get方法:根据Class类型获取类型参数匹配器,首先从Netty内部线程本地Map,获取当前线程类型参数匹配器缓存,从类型参数匹配器缓存,获取参数类型parameterType对应的类型参数匹配器,如果匹配器为空且匹配参数为Object,则匹配器为NOOP,否则,根据参数类型创建ReflectiveMatcher添加到缓存中。
find方法:跟实例object,类型父类parametrizedSuperclass,类型参数名typeParamName,
获取类型参数名object对应的类型参数匹配器,首先从Netty内部线程本地Map,获取当前线程类型参数匹配器缓存,从类型参数匹配器缓存,获取objec类型thisClass对应的类型参数匹配器映射关系,如果不存在object类型对应的类型参数匹配器映射关系,则创建,并添加到缓存中,否则,从object类型对应的类型参数匹配器Map中获取,对应的类型参数匹配器,如果object对应的类型参数匹配器为空,则从父类中获取类型参数名对应的类型的参数匹配器(find0方法获取类型参数名对应的原始类),并将类型与从父类中获取匹配器映射关系,添加到缓存中,否则直接返回匹配器。
find0方法:获取obejct实际类型父类parametrizedSuperclass泛型参数中,类型参数名为typeParamName对应的原始类型过程为,首先获取object的类型currentClass,如果当前类型currentClass的父类为parametrizedSuperclass,获取当前类父类的泛型类型变量,寻找类型参数名对应的类型变量,如果找到,则记录类型变量索引位置,如果索引为位置小于0,即,在object类型父类的类型变量中没有找到typeParamName对应的类型变量,否则,获取当前类的父类泛型类型,如果父类的泛型类型非参数化类型,则返回Object类型,否则,获取父类的实际类型参数,如果实际类型参数为参数化类型,则获取索引对应实际类型参数的原始类型RawType,
如果实际类型为Class,则直接返回Class,如果实际类型参数为泛型数组类型,获取泛型数组类型的泛型组件类型GenericComponentType,如果组件类型为参数化类型,则组件类型为原始类型RawType,如果组件类型为Class,则创建对应的数组实例,并获取实例的类型,如果实际类型参数为类型变量,转化实际类型参数为类型变量v,如果类型变量的声明类不是Class,则返回Object类型,否则设置参数化父类的类型为类型变量v的声明类,如果参数类型父类为thisClass类型,则跳出当前循环,否则返回Object类型,这时,当前类型currentClass的父类为parametrizedSuperclas的情况结束;如果父类不为parametrizedSuperclas,则获取currentClass父类,并设置为当前类继续自旋。自旋的目的是,找到与parametrizedSuperclas类型相等的object类型或父类型。
总结:
简单Inbound通道处理器SimpleChannelInboundHandler<I>,内部有连个变量一个为参数类型匹配器,用来判断通道是否可以处理消息,另一个变量autoRelease,用于控制是否在通道处理消息完毕时,释放消息。读取方法channelRead,首先判断跟定的消息类型是否可以被处理,如果是,则委托给channelRead0,channelRead0待子类实现;如果返回false,则将消息转递给Channel管道线的下一个通道处理器;最后,如果autoRelease为自动释放消息,且消息已处理则释放消息。
发表评论
-
netty NioSocketChannel解析
2017-09-29 12:50 1321netty 抽象BootStrap定义:http://dona ... -
netty Pooled字节buf分配器
2017-09-28 13:00 2057netty 字节buf定义:http://donald-dra ... -
netty Unpooled字节buf分配器
2017-09-26 22:01 2444netty 字节buf定义:http://donald-dra ... -
netty 抽象字节buf分配器
2017-09-26 08:43 1316netty 字节buf定义:http:// ... -
netty 复合buf概念
2017-09-25 22:31 1310netty 字节buf定义:http://donald-dra ... -
netty 抽象字节buf引用计数器
2017-09-22 12:48 1594netty 字节buf定义:http://donald-dra ... -
netty 抽象字节buf解析
2017-09-22 09:00 1844netty 通道接口定义:http://donald-drap ... -
netty 资源泄漏探测器
2017-09-21 09:37 1397netty 通道接口定义:http://donald-drap ... -
netty 字节buf定义
2017-09-20 08:31 2834netty 通道接口定义:http://donald-drap ... -
netty 默认通道配置后续
2017-09-18 08:36 2177netty 通道接口定义:http://donald-drap ... -
netty 默认通道配置初始化
2017-09-17 22:51 2037netty 通道接口定义:http://donald-drap ... -
netty 通道配置接口定义
2017-09-17 14:51 1078netty 通道接口定义:http://donald-drap ... -
netty NioServerSocketChannel解析
2017-09-16 13:01 1877netty ServerBootStrap解析:http:// ... -
netty 抽象nio消息通道
2017-09-15 15:30 1218netty 通道接口定义:http:/ ... -
netty 抽象nio字节通道
2017-09-14 22:39 1202netty 通道接口定义:http:/ ... -
netty 抽象nio通道解析
2017-09-14 17:23 957netty 通道接口定义:http://donald-drap ... -
netty 抽象通道后续
2017-09-13 22:40 1309netty Inboudn/Outbound通道Inv ... -
netty 通道Outbound缓冲区
2017-09-13 14:31 2189netty 通道接口定义:http:/ ... -
netty 抽象Unsafe定义
2017-09-12 21:24 1076netty 通道接口定义:http:/ ... -
netty 抽象通道初始化
2017-09-11 12:56 1855netty 管道线定义-ChannelPipeline:htt ...
相关推荐
在服务端,我们需要创建一个 `ServerBootstrap`,设置好 NIO 事件循环组,然后配置 ChannelPipeline 添加自定义的编解码器和其他必要的处理器,如 `ServerInboundHandler` 用于接收和处理来自客户端的连接和消息。...
`Coder`(编码器)和`Handler`(处理器)是Netty中的两个核心组件,它们分别处理数据的编码和解码以及业务逻辑处理。编码器负责将应用程序对象转换为适合网络传输的数据格式,如ByteBuf;而处理器则负责处理接收到的...
这个“netty简易时间和操作系统查询服务器源码”项目,旨在为初学者提供一个基础的Netty应用实例,帮助理解如何利用Netty进行网络通信,以及如何获取服务器时间及操作系统信息。 首先,让我们深入了解一下Netty。...
这个压缩包中的"Netty简单应答程序"示例,旨在展示如何使用Netty构建一个基本的通信系统,其中客户端能够向服务器发送消息,并接收到服务器的回应。 首先,我们要理解Netty的基本组件。Netty的核心是其Channel...
在“netty简单聊天室”这个项目中,Netty被用来构建一个简单的验证聊天工具,允许用户通过客户端进行实时通信。下面将详细阐述Netty在聊天室中的应用及其相关知识点。 1. **Netty架构**: Netty的核心是它的...
它允许我们配置各种参数,如事件循环组、通道处理器等,然后启动连接或监听。 3. **Pipeline**:Pipeline 是一个处理链,负责对流入和流出 Channel 的数据进行处理。每个 Pipeline 可以包含多个处理器(Handler),...
而通道处理器链(ChannelPipeline)则允许用户自定义数据在网络中传输的处理流程,这提供了高度的灵活性和可扩展性。 Netty 4.1.6版本引入了许多改进和优化。例如,性能提升、内存管理优化、错误处理的增强以及对新...
本项目通过Netty实现了一个简单的聊天消息群发功能,使得多个客户端可以向服务端发送消息,服务端接收到消息后,再广播给所有连接的客户端。这对于构建分布式聊天系统或者实时通知系统非常有用。 首先,我们要理解...
3. **定义Netty服务器**:创建一个Netty服务器,继承自`io.netty.bootstrap.ServerBootstrap`,配置服务器的参数,如端口、通道处理器等。使用`io.netty.channel.ChannelHandlerContext`来处理接收到的网络事件。 4...
ChannelHandler(通道处理器)是业务逻辑的载体,通过ChannelPipeline(通道管道)组织成处理链,实现数据的双向流动。 Netty 4.1.19.Final 版本包含了多个优化和改进,例如更好的内存管理、性能提升以及对新协议的...
4. 核心功能:覆盖了传输(Transports)、缓冲区(Buffers)、通道处理器(ChannelHandler)、编解码器(Codec)以及Netty提供的通道处理器和编解码器。这些都是构建Netty应用时不可或缺的组件和概念。 ***ty示例:...
在服务端,通常需要添加解码器(如 ByteToMessageDecoder)来解析接收到的字节流,以及处理器(如 SimpleChannelInboundHandler)来处理解析后的消息。 3. 绑定端口:通过调用 bind() 方法将 ServerBootstrap 对象与...
在这个入门案例中,你可能会看到这些步骤的实现,包括如何组织项目结构、编写 `.proto` 文件、配置 Netty 通道处理器,以及如何实际运行和测试这个简单的通信系统。这将帮助你理解如何在实际项目中利用 Netty 的异步...
Netty Server端通常会包含一个`ServerBootstrap`,用于设置服务器的各种属性,如事件循环组、通道处理器等。Client端则会使用`Bootstrap`来连接到服务器,同样也需要配置相应的处理器链。 在Server端,我们可以使用...
- **1.2.4 事件与处理器(Events and Handlers)**:Netty中的事件是指发生在通道上的特定条件或状态变化,而处理器则是一组用于处理这些事件的对象。每个处理器都有机会处理事件,并且可以将事件传递给管道中的下一...
注:下载前请查看本人博客文章,看是否...里面包含模拟TCP客户端发送报文工具,硬件厂商提供的协议,服务端(springboot+netty)解析报文源码,源码里整合了redis,不需要可自行删除,如有需要客户端代码,可联系我。
6. **Netty的ChannelHandlerContext**: 在Netty中,`ChannelHandlerContext`是处理I/O事件的关键,它包含了与通道相关的各种操作,如读写、注册事件处理器、关闭通道等。在WebSocket处理器中,我们通常会通过`...
Netty由多个组件构成,如EventLoopGroup(事件循环组)、Bootstrap(启动类)、ChannelHandler(通道处理器)等。EventLoopGroup是线程池的概念,负责执行I/O操作和调用ChannelHandler。Bootstrap则用于配置和启动...
Netty的处理器主要分为两种类型:入站处理器(Inbound Handler)和出站处理器(Outbound Handler)。入站处理器通常处理读取数据、连接事件等事件,出站处理器则处理写入数据、建立连接等请求。 Netty的架构包括了...
- **ChannelHandlerContext**: 提供了与通道相关的上下文信息,用于处理通道事件和调用通道处理器。 - **EventLoop**: 事件循环,负责处理通道上的事件。 - **Pipeline**: 事件处理管道,包含一系列处理器,每个...