使用netty4.0实现Http请求的分发

思路是使用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的话,还需要自己动动脑筋。以上代码,仅仅是抛砖引玉。

 

 

你可能感兴趣的:(java)