思路是使用executor来处理被分发的请求。
主类的代码:
package com.mytest.main; import java.net.InetSocketAddress; import java.util.HashMap; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.mytest.executors.AbstractExecutor; import com.mytest.executors.HelloExecutor; import com.mytest.executors.TestExecutor; import com.mytest.handles.Dispatcher; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.ChannelPipeline; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.timeout.IdleStateHandler; public class StartupDisPatchClass { private static Logger logger = LoggerFactory.getLogger(StartupDisPatchClass.class); private void launchServer() { EventLoopGroup bossGroup = new NioEventLoopGroup(Runtime.getRuntime().availableProcessors()/2+1); EventLoopGroup workerGroup = new NioEventLoopGroup(Runtime.getRuntime().availableProcessors()/2+1); try { //服务启动 ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(this.new ChildChannelHandler()) .option(ChannelOption.SO_BACKLOG, 1024) .option(ChannelOption.SO_REUSEADDR, true) .option(ChannelOption.SO_KEEPALIVE, true); Channel ch = b.bind(new InetSocketAddress(9000)).sync().channel(); logger.info("httpserver started on port[" + 9000+ "]"); ch.closeFuture().sync(); } catch (InterruptedException e) { logger.error(e.getMessage(),e); } finally { //服务关闭 bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } public static void main(String [] args) throws InterruptedException { new StartupDisPatchClass().launchServer(); } class ChildChannelHandler extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel arg0) throws Exception { logger.info("server initChannel.."); ChannelPipeline p = arg0.pipeline(); //监控线程空闲事件 p.addLast("idleStateHandler", new IdleStateHandler(60, 60, 30)); //将httprequest和httpresponse处理合并成一个 p.addLast("ServiceDecoder", new HttpServerCodec()); //控制http消息的组合,参数表示支持的内容最大长度 p.addLast("httpAggregator",new HttpObjectAggregator(1024)); Dispatcher dispatcher = new Dispatcher(); Map<String, Class<? extends AbstractExecutor>> apiMappings = new HashMap<String, Class<? extends AbstractExecutor>>(); apiMappings.put("hello", HelloExecutor.class); apiMappings.put("test", TestExecutor.class); dispatcher.setApiMappings(apiMappings); p.addLast("dispatcher",dispatcher); } } }
分发器的代码:
package com.mytest.handles; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import com.mytest.executors.AbstractExecutor; import com.mytest.executors.DefaultExecutor; import com.mytest.utils.UrlUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.handler.codec.http.FullHttpRequest; public class Dispatcher extends ChannelInboundHandlerAdapter { private Map<String,Class<? extends AbstractExecutor>> apiMappings = new HashMap<String,Class<? extends AbstractExecutor>>(); public Map<String, Class<? extends AbstractExecutor>> getApiMappings() { return apiMappings; } public void setApiMappings(Map<String, Class<? extends AbstractExecutor>> apiMappings) { this.apiMappings = apiMappings; } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof FullHttpRequest) { FullHttpRequest request = (FullHttpRequest) msg; String url = request.getUri(); System.out.println(url); ExecutorService executorService = Executors.newFixedThreadPool(10); String apiName = UrlUtil.getApiName(url); AbstractExecutor executor = null; if (this.apiMappings.containsKey(apiName)) { //实现了分发 executor = this.apiMappings.get(apiName).newInstance(); }else{ //默认处理逻辑 executor = new DefaultExecutor(); } executor.setCtx(ctx); executor.setMsg(request); executorService.submit(executor); } } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { } }
excutor抽象类
package com.mytest.executors; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpResponse; public abstract class AbstractExecutor extends Thread { protected String apiName; protected ChannelHandlerContext ctx; protected FullHttpRequest msg; protected FullHttpResponse response; public ChannelHandlerContext getCtx() { return ctx; } public void setCtx(ChannelHandlerContext ctx) { this.ctx = ctx; } public FullHttpRequest getMsg() { return msg; } public void setMsg(FullHttpRequest msg) { this.msg = msg; } public FullHttpResponse getResponse() { return response; } public void setResponse(FullHttpResponse response) { this.response = response; } public String getApiName() { return apiName; } public void setApiName(String apiName) { this.apiName = apiName; } public abstract boolean preWork(); public abstract boolean doWork(); public abstract boolean postWork(); public final void run() { boolean flag = this.preWork(); if (flag==true) { this.doWork(); } if (flag== true) { this.postWork(); } if (this.msg!= null) { System.out.println("From " + this.getApiName() + " executor\t" + msg.getUri()); } this.ctx.writeAndFlush(this.getResponse()); this.ctx.close(); } }
抽象类的一个子类:默认处理单元
package com.mytest.executors; import io.netty.buffer.Unpooled; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpVersion; import io.netty.util.CharsetUtil; public class DefaultExecutor extends AbstractExecutor { @Override public boolean preWork() { return true; } @Override public boolean doWork() { String content = "{\"e\":0,\"api\":\"default\"}"; FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.copiedBuffer(content.toCharArray(), CharsetUtil.UTF_8)); this.setApiName("default"); this.setResponse(response); return true; } @Override public boolean postWork() { return true; } }
还有一个处理url的工具类:
package com.mytest.utils; public class UrlUtil { public static String getApiName(String url){ String result = ""; try { int i = url.lastIndexOf("/"); String substr = url.substring(i+1); int end = substr.indexOf("?"); if (end >0) { result = substr.substring(0,substr.indexOf("?")); }else { result = substr.substring(0); } } catch (Exception e) { e.printStackTrace(); } return result; } public static void main(String [] args ) { String url="/hello?uid=1"; System.out.println(UrlUtil.getApiName(url)); url = "/hello1"; System.out.println(UrlUtil.getApiName(url)); } }
大概是这样。如果需要引入spring的话,还需要自己动动脑筋。以上代码,仅仅是抛砖引玉。