思路是使用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 {
@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> apiMappings = new HashMap>();
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> apiMappings = new HashMap>();
public Map> getApiMappings() {
return apiMappings;
}
public void setApiMappings(Map> 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的话,还需要自己动动脑筋。以上代码,仅仅是抛砖引玉。