package org.leo.web.core; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpRequestDecoder; import io.netty.handler.codec.http.HttpResponseEncoder; import io.netty.handler.stream.ChunkedWriteHandler; import io.netty.util.concurrent.DefaultEventExecutorGroup; import io.netty.util.concurrent.EventExecutorGroup; import io.netty.util.concurrent.RejectedExecutionHandlers; /** * Netty Handler 初始化类 * * @author Leo * @date 2018/3/29 */ final class HandlerInitializer extends ChannelInitializer<SocketChannel> { private int maxContentLength = 0; /** * 业务线程池线程数 * 可通过 -Dhttp.executor.threads 设置 */ private static int eventExecutorGroupThreads = 0; /** * 业务线程池队列长度 * 可通过 -Dhttp.executor.queues 设置 */ private static int eventExecutorGroupQueues = 0; static { eventExecutorGroupThreads = Integer.getInteger("http.executor.threads", 0); if(eventExecutorGroupThreads == 0) { eventExecutorGroupThreads = Runtime.getRuntime().availableProcessors() * 2; } eventExecutorGroupQueues = Integer.getInteger("http.executor.queues", 0); if(eventExecutorGroupQueues == 0) { eventExecutorGroupQueues = 1024; } } /** * 业务线程组 */ private static final EventExecutorGroup eventExecutorGroup = new DefaultEventExecutorGroup( eventExecutorGroupThreads, new ThreadFactory() { private AtomicInteger threadIndex = new AtomicInteger(0); @Override public Thread newThread(Runnable r) { return new Thread(r, "HttpRequestHandlerThread_" + this.threadIndex.incrementAndGet()); } }, eventExecutorGroupQueues, RejectedExecutionHandlers.reject()); public HandlerInitializer(int maxContentLength) { this.maxContentLength = maxContentLength; } @Override protected void initChannel(SocketChannel ch) throws Exception { /* * ChannelInboundHandler按照注册的先后顺序执行,ChannelOutboundHandler按照注册的先后顺序逆序执行。 * HttpRequestDecoder、HttpObjectAggregator、HttpHandler为InboundHandler * HttpContentCompressor、HttpResponseEncoder为OutboundHandler * 在使用Handler的过程中,需要注意: * 1、ChannelInboundHandler之间的传递,通过调用 ctx.fireChannelRead(msg) 实现;调用ctx.write(msg) 将传递到ChannelOutboundHandler。 * 2、ctx.write()方法执行后,需要调用flush()方法才能令它立即执行。 * 3、ChannelOutboundHandler 在注册的时候需要放在最后一个ChannelInboundHandler之前,否则将无法传递到ChannelOutboundHandler。 * 4、Handler的消费处理放在最后一个处理。 */ ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast("decoder", new HttpRequestDecoder()); pipeline.addLast("aggregator", new HttpObjectAggregator(maxContentLength)); pipeline.addLast("encoder", new HttpResponseEncoder()); // 启用gzip(由于使用本地存储文件,不能启用gzip) //pipeline.addLast(new HttpContentCompressor(1)); pipeline.addLast(new ChunkedWriteHandler()); // 将HttpRequestHandler放在业务线程池中执行,避免阻塞worker线程。 pipeline.addLast(eventExecutorGroup, "httpRequestHandler", new HttpRequestHandler()); } }