Tomcat使用Netty实现

  • 定义配置文件,指定 url,与对应的执行类
servlet.one.url=/firstServlet.do
servlet.one.className=com.rt.netty.tomcat.servlet.FirstServlet

servlet.two.url=/secondServlet.do
servlet.two.className=com.rt.netty.tomcat.servlet.SecondServlet
  • 读取配置文件,初始化 Servlet 容器
private Map<String, RTServlet> servletMapping = new HashMap<String, RTServlet>();
private Properties webxml = new Properties();
private void init(){
	//加载web.xml文件,同时初始化 ServletMapping对象
	try{
		String WEB_INF = this.getClass().getResource("/").getPath();
		FileInputStream fis = new FileInputStream(WEB_INF + "web.properties");
		webxml.load(fis);
		for (Object k : webxml.keySet()) {
			String key = k.toString();
			if(key.endsWith(".url")){
				String servletName = key.replaceAll("\\.url$", "");
				String url = webxml.getProperty(key);
				String className = webxml.getProperty(servletName + ".className");
				RTServlet obj = (RTServlet)Class.forName(className).newInstance();
				servletMapping.put(url, obj);
			}
		}
	}catch(Exception e){
		e.printStackTrace();
	}
}	
  • Netty 启动对本地IP指定端口的监听
//Netty封装了NIO,Reactor模型,Boss,worker
// Boss线程
EventLoopGroup bossGroup = new NioEventLoopGroup();
// Worker线程
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
	// Netty服务
	//ServetBootstrap   ServerSocketChannel
	ServerBootstrap server = new ServerBootstrap();
	// 链路式编程
	server.group(bossGroup, workerGroup)
			// 主线程处理类,看到这样的写法,底层就是用反射
			.channel(NioServerSocketChannel.class)
			// 子线程处理类 , Handler
			.childHandler(new ChannelInitializer<SocketChannel>() {
				// 客户端初始化处理
				protected void initChannel(SocketChannel client) throws Exception {
					// 无锁化串行编程
					//Netty对HTTP协议的封装,顺序有要求
					// HttpResponseEncoder 编码器
					client.pipeline().addLast(new HttpResponseEncoder());
					// HttpRequestDecoder 解码器
					client.pipeline().addLast(new HttpRequestDecoder());
					// 业务逻辑处理
					client.pipeline().addLast(new RTTomcatHandler());
				}
			})
			// 针对主线程的配置 分配线程最大数量 128
			.option(ChannelOption.SO_BACKLOG, 128)
			// 针对子线程的配置 保持长连接
			.childOption(ChannelOption.SO_KEEPALIVE, true);
	// 启动服务器
	ChannelFuture f = server.bind(port).sync();
	System.out.println("Tomcat 已启动,监听的端口是:" + port);
	f.channel().closeFuture().sync();
}catch (Exception e){
	e.printStackTrace();
}finally {
	// 关闭线程池
	bossGroup.shutdownGracefully();
	workerGroup.shutdownGracefully();
}
  • 处理对指定端口的网络连接
public class RTTomcatHandler extends ChannelInboundHandlerAdapter {
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		if (msg instanceof HttpRequest){
			HttpRequest req = (HttpRequest) msg;
			// 转交给我们自己的request实现
			RTRequest request = new RTRequest(ctx,req);
			// 转交给我们自己的response实现
			RTResponse response = new RTResponse(ctx,req);
			// 实际业务处理
			String url = request.getUrl();
			if(servletMapping.containsKey(url)){
				servletMapping.get(url).service(request, response);
			}else{
				response.write("404 - Not Found");
			}
		}
	}
	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
	}
}
  • 封装请求与响应对象
private ChannelHandlerContext ctx;
private HttpRequest req;
public RTRequest(ChannelHandlerContext ctx, HttpRequest r
	this.ctx = ctx;
	this.req = req;
}
public String getUrl() {
	return req.uri();
}
public String getMethod() {
	return req.method().name();
}
public class RTResponse {

	//SocketChannel的封装
	private ChannelHandlerContext ctx;

	private HttpRequest req;

	public RTResponse(ChannelHandlerContext ctx, HttpRequest req) {
		this.ctx = ctx;
		this.req = req;
	}

	public void write(String out) throws Exception {
		try {
			if (out == null || out.length() == 0) {
				return;
			}
			// 设置 http协议及请求头信息
			FullHttpResponse response = new DefaultFullHttpResponse(
				// 设置http版本为1.1
				HttpVersion.HTTP_1_1,
				// 设置响应状态码
				HttpResponseStatus.OK,
				// 将输出值写出 编码为UTF-8
				Unpooled.wrappedBuffer(out.getBytes("UTF-8")));

			response.headers().set("Content-Type", "text/html;");
			// 当前是否支持长连接
//            if (HttpUtil.isKeepAlive(r)) {
//                // 设置连接内容为长连接
//                response.headers().set(CONNECTION, HttpHeaderValues.KEEP_ALIVE);
//            }
			ctx.write(response);
		} finally {
			ctx.flush();
			ctx.close();
		}
	}
}
  • RTServlet 请求分发
public abstract class RTServlet {
	
	public void service(RTRequest request, RTResponse response) throws Exception{
		
		//由service方法来决定,是调用doGet或者调用doPost
		if("GET".equalsIgnoreCase(request.getMethod())){
			doGet(request, response);
		}else{
			doPost(request, response);
		}

	}
	
	public abstract void doGet(RTRequest request, RTResponse response) throws Exception;
	
	public abstract void doPost(RTRequest request, RTResponse response) throws Exception;
}
  • servlet 执行类

	public void doGet(RTRequest request, RTResponse response) throws Exception {
		this.doPost(request, response);
	}

	public void doPost(RTRequest request, RTResponse response) throws Exception {
		response.write("This is rt First Serlvet");
	}

}
public class SecondServlet extends RTServlet {

	public void doGet(RTRequest request, RTResponse response) throws Exception {
		this.doPost(request, response);
	}

	public void doPost(RTRequest request, RTResponse response) throws Exception {
		response.write("This is rt Second Serlvet");
	}

}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值