基于netty手寫Tomcat

作者:MovW
原文:http://suo.im/5Ar7t8
netty 簡介
Netty一個(gè)基于NIO的客戶、服務(wù)器端的編程框架
1.環(huán)境準(zhǔn)備
maven依賴
??
????????????io.netty
????????????netty-all
????????????4.1.42.Final
??
12345
RequestMethodEnum 請(qǐng)求方式
public?enum?RequestMethodEnum?{
??GET("GET"),
??POST("POST");
??public?String?code;
??RequestMethodEnum(String?code)?{
????this.code=code;
??}}12345678
ParentServlet 父類servlet
public?abstract?class?ParentServlet?{
??public?void?service(ParentRequest?request,?ParentResponse?response)?throws?Exception?{
????//service 方法決定調(diào)用doGet、doPost;
????if?(RequestMethodEnum.GET.code.equalsIgnoreCase(request.getMethod()))?{
??????doGet(request,?response);
????}?else?{
??????doPost(request,?response);
????}
??}
??protected?abstract?void?doPost(ParentRequest?request,?ParentResponse?response)?throws?Exception;
??protected?abstract?void?doGet(ParentRequest?request,?ParentResponse?response)?throws?Exception;
}
12345678910111213141516
FirstServlet
public?class?FirstServlet?extends?ParentServlet?{
??@Override
??protected?void?doPost(ParentRequest?request,?ParentResponse?response)?throws?Exception?{
????response.write("This?is?the?first");
??}??@Override
??protected?void?doGet(ParentRequest?request,?ParentResponse?response)?throws?Exception?{
????this.doPost(request,response);
??}}1234567891011
SecondServlet
public?class?SecondServlet?extends?ParentServlet?{
??@Override
??protected?void?doPost(ParentRequest?request,?ParentResponse?response)?throws?Exception?{
????response.write("this?is?the?second");
??}??@Override
??protected?void?doGet(ParentRequest?request,?ParentResponse?response)?throws?Exception?{
????this.doPost(request,response);
??}}1234567891011
ParentRequest
public?class?ParentRequest?{
??private?String?method;
??private?String?url;
??public?String?getUrl()?{
????return?url;
??}??public?String?getMethod()?{
????return?method;
??}}1234567891011121314
ParentResponse
public?class?ParentResponse?{
??private?OutputStream?out;
??public?ParentResponse?(OutputStream?out)?{
????this.out?=?out;
??}??public?void?write(String?s)?throws?Exception{
????//輸出也要遵循HTTP
????//狀態(tài)碼為200
????StringBuilder?sb?=?new?StringBuilder();
????sb.append("HTTP/1.1?200?OK?\n")
??????.append("Content-Type:?text/html;\n")
??????.append("\r\n")
??????.append(s);
????out.write(sb.toString().getBytes());
??}
}
1234567891011121314151617
web.properties
servlet.first.url=/first
servlet.first.className=com.aiden.servlet.FirstServletservlet.second.url=/secondservlet.second.className=com.aiden.servlet.SecondServlet1234
2.基于傳統(tǒng)I/O手寫Tomcat
修改ParentRequest
public?class?ParentRequest?{
??private?String?method;
??private?String?url;
??public?ParentRequest(InputStream?in)?{
????try?{
??????String?content?=?"";
??????byte[]?buff?=?new?byte[1024];
??????int?len?=?0;
??????if?((len?=?in.read(buff))?>?0)?{
????????content?=?new?String(buff,0,len);
??????}??????String?line?=?content.split("\\n")[0];
??????String?[]?arr?=?line.split("\\s");
??????this.method?=?arr[0];
??????System.out.println(method);
??????this.url?=?arr[1].split("\\?")[0];
????}?catch?(IOException?e)?{
??????e.printStackTrace();????}??}??public?String?getUrl()?{
????return?url;
??}??public?String?getMethod()?{
????return?method;
??}}12345678910111213141516171819202122232425262728293031
編寫tomcatStart類
public?class?TomcatStart?{
??private?int?port?=?8080;
??private?ServerSocket?server;
??private?Map?servletMapping?=?new?HashMap();
??private?Properties?webProperties?=?new?Properties();
??private?void?init()?{
????try?{
??????String?WEB_INF?=?this.getClass().getResource("/").getPath();
??????FileInputStream?fis?=?new?FileInputStream(WEB_INF?+?"web.properties");
??????webProperties.load(fis);??????for?(Object?k?:?webProperties.keySet())?{
????????String?key?=?k.toString();
????????if?(key.endsWith(".url"))?{
??????????String?servletName?=?key.replaceAll("\\.url$",?"");
??????????String?url?=?webProperties.getProperty(key);
??????????String?className?=?webProperties.getProperty(servletName?+?".className");
??????????//單實(shí)例??多線程
??????????ParentServlet?obj?=?(ParentServlet)?Class.forName(className).newInstance();
??????????servletMapping.put(url,?obj);
????????}
??????}
????}?catch?(Exception?e)?{
??????e.printStackTrace();
????}
??}
??public?void?start()?{
????//1.加載配置類,初始化servletMapping
????init();
????try?{
??????//2.綁定端口啟動(dòng)
??????server?=?new?ServerSocket(this.port);
??????System.out.println("Tomcat 已啟動(dòng),監(jiān)聽端口是:"?+?this.port);
??????//3.等待用戶請(qǐng)求,用一個(gè)死循環(huán)
??????while?(true)?{
????????Socket?client?=?server.accept();
????????//4.http?請(qǐng)求
????????process(client);
??????}
????}?catch?(IOException?e)?{
??????e.printStackTrace();
????}
??}
??private?void?process(Socket?client)?throws?IOException?{
????InputStream?is?=?null;
????OutputStream?os?=?null;
????try?{
??????is?=?client.getInputStream();
??????os?=?client.getOutputStream();
??????//5.Request(inputstream)?Response?(outputstream)
??????ParentRequest?request?=?new?ParentRequest(is);
??????ParentResponse?response?=?new?ParentResponse(os);
??????//6.從協(xié)議內(nèi)容中獲取url?映射相應(yīng)的servlet
??????String?url?=?request.getUrl();
??????if?(servletMapping.containsKey(url))?{
????????//7.調(diào)用實(shí)例化對(duì)象的service方法
????????servletMapping.get(url).service(request,?response);
??????}?else?{
????????response.write("404?-?Not?Found");
??????}
????}?catch?(Exception?e)?{
??????e.printStackTrace();
????}?finally?{
??????if?(os?!=?null)?{
????????os.flush();
????????os.close();
??????}
??????if?(is?!=?null)?{
????????is.close();
??????}
??????client.close();
????}
??}
??public?static?void?main(String[]?args)?{
????//啟動(dòng)
????new?TomcatStart().start();
??}
}
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
3.基于netty手寫Tomcat
修改ParentRequest
public?class?ParentRequest?{
??private?ChannelHandlerContext?ctx;
??private?HttpRequest?req;
??public?ParentRequest(ChannelHandlerContext?ctx,?HttpRequest?req)?{
????this.ctx?=?ctx;
????this.req?=?req;
??}??public?String?getUrl()?{
????return?req.uri();
??}??public?String?getMethod()?{
????return?req.method().name();
??}??public?Map>?getParameters()?{
????QueryStringDecoder?decoder?=?new?QueryStringDecoder(req.uri());
????return?decoder.parameters();
??}??public?String?getParameter(String?name)?{
????Map>?params?=?getParameters();
????List?param?=?params.get(name);
????if?(null?==?param)?{
??????return?null;
????}?else?{
??????return?param.get(0);
????}??}}123456789101112131415161718192021222324252627282930313233
修改ParentResponse
public?class?ParentResponse?{
??//SocketChannel的封裝??private?ChannelHandlerContext?ctx;??private?HttpRequest?req;??public?ParentResponse(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;
??????}??????//?設(shè)置?http協(xié)議及請(qǐng)求頭信息??????FullHttpResponse?response?=?new?DefaultFullHttpResponse(????????//?設(shè)置http版本為1.1
????????HttpVersion.HTTP_1_1,????????//?設(shè)置響應(yīng)狀態(tài)碼????????HttpResponseStatus.OK,????????//?將輸出值寫出?編碼為UTF-8
????????Unpooled.wrappedBuffer(out.getBytes("UTF-8")));
??????response.headers().set("Content-Type",?"text/html;");
??????ctx.write(response);
????}?finally?{??????ctx.flush();
??????ctx.close();
????}??}}12345678910111213141516171819202122232425262728293031323334
修改TomcatStart
public?class?TomcatStart?{
??private?int?port?=?8080;
??private?Map?servletMapping?=?new?HashMap();
??private?Properties?webProperties?=?new?Properties();
??private?void?init()?{
????try?{
??????String?WEB_INF?=?this.getClass().getResource("/").getPath();
??????FileInputStream?fis?=?new?FileInputStream(WEB_INF?+?"web.properties");
??????webProperties.load(fis);??????for?(Object?k?:?webProperties.keySet())?{
????????String?key?=?k.toString();
????????if?(key.endsWith(".url"))?{
??????????String?servletName?=?key.replaceAll("\\.url$",?"");
??????????String?url?=?webProperties.getProperty(key);
??????????String?className?=?webProperties.getProperty(servletName?+?".className");
??????????//單實(shí)例??多線程
??????????ParentServlet?obj?=?(ParentServlet)?Class.forName(className).newInstance();
??????????servletMapping.put(url,?obj);
????????}
??????}
????}?catch?(Exception?e)?{
??????e.printStackTrace();
????}
??}
??public?void?start()?{
????//1.加載配置類,初始化servletMapping
????init();
????//?Netty??NIO?Reactor模型?Boss?Worker
????//Boss?線程
????EventLoopGroup?bossGroup?=?new?NioEventLoopGroup();
????//Work線程
????EventLoopGroup?workGroup?=?new?NioEventLoopGroup();
????ServerBootstrap?server?=?null;
????try?{
??????//創(chuàng)建對(duì)象
??????server?=?new?ServerBootstrap();
??????//配置參數(shù)
??????//鏈?zhǔn)骄幊?br>??????server.group(bossGroup,?workGroup)
????????//主線程處理類,
????????.channel(NioServerSocketChannel.class)
????????//子線程處理類
????????.childHandler(new?ChannelInitializer()?{
??????????@Override
??????????protected?void?initChannel(SocketChannel?client)?throws?Exception?{
????????????//無鎖化串行編程
????????????//netty對(duì)http的封裝?對(duì)順序有要求
????????????//httpResponseEncoder?編碼器
????????????client.pipeline().addLast(new?HttpResponseEncoder());
????????????//httprequestDecoder?解碼器
????????????client.pipeline().addLast(new?HttpRequestDecoder());
????????????//業(yè)務(wù)處理器
????????????client.pipeline().addLast(new?TomcatHandler());
??????????}
????????})
????????//主線程?線程最大數(shù)量128
????????.option(ChannelOption.SO_BACKLOG,?128)
????????//子線程配置?保存長連接
????????.childOption(ChannelOption.SO_KEEPALIVE,?true);
??????ChannelFuture?f?=?server.bind(port).sync();
??????System.out.println("Tomcat 已啟動(dòng),監(jiān)聽端口是:"?+?this.port);
??????f.channel().closeFuture().sync();
????}?catch?(Exception?e)?{
??????e.printStackTrace();
????}?finally?{
??????bossGroup.shutdownGracefully();
??????workGroup.shutdownGracefully();
????}
??}
??public?class?TomcatHandler?extends?ChannelInboundHandlerAdapter?{
????@Override
????public?void?channelRead(ChannelHandlerContext?ctx,?Object?msg)?throws?Exception?{
??????if?(msg?instanceof?HttpRequest)?{
????????System.out.println("hello?request");
????????HttpRequest?req?=?(HttpRequest)?msg;
????????ParentRequest?request?=?new?ParentRequest(ctx,?req);
????????ParentResponse?response?=?new?ParentResponse(ctx,?req);
????????String?url?=?request.getUrl();
????????if?(servletMapping.containsKey(url))?{
??????????//7.調(diào)用實(shí)例化對(duì)象的service方法
??????????servletMapping.get(url).service(request,?response);
????????}?else?{
??????????response.write("404?-?Not?Found");
????????}
??????}
????}
??}
??public?static?void?main(String[]?args)?{
????//啟動(dòng)
????new?TomcatStart().start();
??}
}
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
4.訪問
http://localhost:8080/first

好文章,我在看
好文章,我在看
評(píng)論
圖片
表情

