netty源碼解析(4.0)-16 ChannelHandler概覽

  本章開始分析ChannelHandler實現代碼。ChannelHandler是netty爲開發者提供的實現定製業務的主要接口,開發者在使用netty時,最主要的工做就是實現本身的ChannelHandler。ChannelHandler在設計上須要和ChannelPipeline配合共同實現pipeline的事件傳遞能力,這要求ChannelHandler須要實現一些固定的基本功能。因爲這個緣由,若是讓用戶本身完整地實現,會顯得比較麻煩。爲此netty實現類一系列的類來幫助開發者以簡單的方式實現本身的ChannelHandler,並且只須要把注意力聚焦在本身業務和定製的部分上。在netty中,ChannelHandler不單單是幾個簡單的接口定義,而是一系列的實現,這些實現針對不一樣的問題,其中包括:git

  單一功能性的Handler實現: github

    IP過濾,實現IP黑白名單功能。算法

    寫日誌。服務器

    SSL實現。app

    超時處理。異步

      編碼和序列化格式的支持:tcp

    base64ide

            gzip,snappy壓縮算法ui

      protoBuf編碼

    String

    自定義數據包格式。

  常見應用層協議:

    http/https(後面的版本還支持http2)

    haprox

 

ChannelHandler體系結構

  上圖上的全部接口的實現都位於io.netty.channel包中,其中,ChannelHandler是最頂層抽象的接口,ChannelInboundHandler是處理inbound事件的接口,ChannelOutboundHandler是處理outbound事件的接口。ChannelHandlerApapter是與I/O無關的抽象實現。ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter是最簡單的實現,他們什麼都沒作,僅僅使用ChannelHandlerContext把事件傳遞到pipleline中下一個handler,若是你不清楚在正在處理事件以後如何傳遞事件,請參考這兩個類中的代碼。好比,ChannelInboundAdapter中是這樣傳遞read事件的:

1 @Override
2 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
3         ctx.fireChannelRead(msg);
4 }

 

CombinedChannelDuplexhandler兼具ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter的能力。若是你想讓一個Handler同時處理inbound和outbound事件,請繼承這個類。

 

ChannelHandler的共享和獨佔模式

  netty爲ChannelHandler設計了兩種模式,若是用ChannelHandler.Sharable修飾你的Handler, 那麼這個Handler實例就是可共享的,不然它就是被某個Channel獨佔的。

@ChannelHandler.Sharable
public class MyHandler extends ChannelInboundHandler{
}

 

  這個MyHandler的實例是能夠被不一樣的Channel共享的。在初始化Channel的時候能夠這加入到pipeline中:

1 public class HandlerInitializer extends ChannelInitializer<SocketChanne>{
2     private static MyHandler handler   = new MyHandler();
3     
4     @Override
5     protected void initChannel(SocketChannel ch) throws Exception{
6         ch.pipeline().addLast(handler);
7     }
8 }

 

  若是去掉@ChannelHandler.Sharable,它就是獨佔的,默認的都是獨佔。它能夠這樣用:

public class HandlerInitializer extends ChannelInitializer<SocketChanne>{
     
     @Override
     protected void initChannel(SocketChannel ch) throws Exception{
         ch.pipeline().addLast(new MyHandler());
     }
}

 

  ChannelHandlerAdapter的isSharable方法負責處理@ChannelHandler.Sharable:

public boolean isSharable() {
        /**
         * Cache the result of {@link Sharable} annotation detection to workaround a condition. We use a
         * {@link ThreadLocal} and {@link WeakHashMap} to eliminate the volatile write/reads. Using different
         * {@link WeakHashMap} instances per {@link Thread} is good enough for us and the number of
         * {@link Thread}s are quite limited anyway.
         *
         * See <a href="https://github.com/netty/netty/issues/2289">#2289</a>.
         */
        Class<?> clazz = getClass();
        Map<Class<?>, Boolean> cache = InternalThreadLocalMap.get().handlerSharableCache();
        Boolean sharable = cache.get(clazz);
        if (sharable == null) {
            sharable = clazz.isAnnotationPresent(Sharable.class);
            cache.put(clazz, sharable);
        }
        return sharable;
    }

 

  如今已經清楚了@ChannelHandler.Sharable影響和用法。那麼問題來了,netty爲何要設計這樣一個東西,它解決了什麼問題呢?弄清這個問題以前,咱們先來弄清楚ChannelHandler的做用。每一個ChannelHandler實例都在Channel的pipeline上佔據一個節點,每一個節點帶表明了事件處理流水線上的一道工序,具體每道工序是什麼,由開發者本身定義和實現。整體來講,netty把工序分紅兩種類型: 有狀態的和無狀態的。有狀態的就是獨佔的,無狀態的是能夠共享的。有狀態和無狀態這個兩個概念太過於抽象。舉個例子,http協議是一個基於TCP的應用層協議,實現這個協議的時候有一道工序是從tcp流中讀到一個完整http數據報,tcp不保證每次read都恰好是一個完整的http數據報,頗有多是不完整的,這時候要把不完整的數據保存在緩衝區中, 下次read到數據以後追加到緩衝區,直到獲得一個完整的http數據報。處理這道工序的Handler是有狀態的,必須使用獨佔的Handler。

  一個Handler的實例是否能夠共享,由它處理的工序決定的。即便netty沒有設計這種獨佔/共享模式,開發者也應該能夠把握好Handler的用法。

 

 經常使用的功能性Handler

  io.netty.handler包中是netty提供的經常使用的功能性的handler:

  io.netty.handler.ipfilter.RuleBasedIpFilter  使用IpFilterRule過過濾遠程地址。

  io.netty.handler.ipfilter.UniqueIpFilter  一個地址只容許和服務器創建一個鏈接。

  io.netty.handler.logging.LoggingHandler 異步讀/寫日誌。

  io.netty.handler.stream.ChunkedWriteHandler 異步讀/寫文件。

  io.netty.handler.timeout.IdleStateHandler  超時觸發空閒狀態事件。

  io.netty.handler.timeout.ReadTimeoutHandler 超時沒有收到數據斷開鏈接。

  io.netty.handler.timeout.WriteTimeoutHandler 超時沒有寫數據斷開鏈接。  

相關文章
相關標籤/搜索