手写 tomcat (nio)
下载 :demo
测试:
项目结构:
public class NIOSocketServerForTomcat { private String host = "127.0.0.1"; private int port = 8080; //private ExecutorService exec = Executors.newFixedThreadPool(60); private ExecutorService exec = new ThreadPoolExecutor(60, 60, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(2000)); private ServerSocketChannel serverSocketChannel; private Selector selector; private NIOSocketServerForTomcat init(){ this.host = "127.0.0.1"; this.port = 8080; return this; } private void start() { try { serverSocketChannel= ServerSocketChannel.open(); serverSocketChannel.configureBlocking(false); serverSocketChannel.bind(new InetSocketAddress(8080)); selector = Selector.open(); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); while (true) { selector.select(1000); Set<SelectionKey> selectedKeys = selector.selectedKeys(); Iterator<SelectionKey> iterator = selectedKeys.iterator(); while (iterator.hasNext()) { SelectionKey key = iterator.next(); iterator.remove(); if(key.isAcceptable()){ SocketChannel channel = serverSocketChannel.accept(); channel.configureBlocking(false); channel.register(selector,SelectionKey.OP_READ ); } else if(key.isReadable()) { SocketChannel channel = (SocketChannel) key.channel(); channel.configureBlocking(false); exec.submit(new NIOServerHanddler(channel)); key.cancel(); } } } } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { new NIOSocketServerForTomcat().init().start() ; } }
public class NIOServerHanddler implements Runnable { private SocketChannel channel; public NIOServerHanddler(SocketChannel channel) { this.channel = channel; } @Override public void run() { try { ByteBuffer bb = ByteBuffer.allocate(1024); channel.read(bb); bb.flip(); byte[] array = bb.array(); bb.clear(); System.out.println(new String(array)); HttpServletRequest req = new HttpServletRequest(new String (array)); System.out.println(FastJsonUtils.toJSONString(req)); HttpServletResponse resp = new HttpServletResponse(channel); Map<String, XmlServletEntity> handdlerMapping = HttpServletContext.getInstace().getHanddlerMapping(); XmlServletEntity target = null; for (XmlServletEntity entity : handdlerMapping.values()) { if (!"".equals(req.getUrl()) &&!"/".equals(req.getUrl()) && req.getUrl().startsWith(entity.getServletpattern())) { target = entity; } } if (null == target) { RespEntity respEntity = new RespEntity(); respEntity.setCode(RespEnums.RESP_ERROR_NOT_FOUND.getCode()); respEntity.setMsg(RespEnums.RESP_ERROR_NOT_FOUND.getDesc()); resp.write(FastJsonUtils.toJSONString(respEntity)); }else{ try { Class<?> clazz = Class.forName(target.getServletClass()); HttpServlet httpServlet =(HttpServlet) clazz.newInstance(); httpServlet.service(req, resp); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } } catch (IOException e) { e.printStackTrace(); }finally{ try { if (channel != null) { channel.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
public class HttpServlet { public void service(HttpServletRequest reqest,HttpServletResponse response){ String method = reqest.getMethod(); if ("GET".equalsIgnoreCase(method)){ this.doGet(reqest, response); } else if ("POST".equalsIgnoreCase(method)) { this.doPost(reqest, response); } } public void doGet(HttpServletRequest reqest,HttpServletResponse response){ } public void doPost(HttpServletRequest reqest,HttpServletResponse response){ } }
public class HttpServletRequest { private String CHAR_ENTER = "\r\n"; private String CHAR_SPACE = " "; private String CHAR_GET = "GET"; private String CHAR_POST = "POST"; private String CHAR_URL_SPLIT = "?"; private String CHAR_PARAMS_SPLIT = "&"; private String CHAR_PARAMS_KEY_VALUE_SPLIT = "="; private String CHAR_HEADS_KEY_VALUE_SPLIT = ": "; private String method; private String url; private String host; private Map<String,Object> parameters = new HashMap<String, Object>(); private Map<String,Object> headers = new HashMap<String, Object>(); // GET /web/users/user?userName=baoyou&pwd=123456 HTTP/1.1 // Host: localhost:8080 // Connection: keep-alive // Upgrade-Insecure-Requests: 1 // User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36 // Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 // Accept-Encoding: gzip, deflate, sdch, br // Accept-Language: zh-CN,zh;q=0.8 // Cookie: __guid=111872281.3385020722635865000.1513231215978.7585 // POST /web/users/user HTTP/1.1 // Host: localhost:8080 // Connection: keep-alive // Content-Length: 26 // Cache-Control: max-age=0 // Origin: null // Upgrade-Insecure-Requests: 1 // User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36 // Content-Type: application/x-www-form-urlencoded // Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*;q=0.8 // Accept-Encoding: gzip, deflate, br // Accept-Language: zh-CN,zh;q=0.8 // Cookie: __guid=111872281.3385020722635865000.1513231215978.7585 // // userName=111&password=1111 public HttpServletRequest(String requestString) { String[] arr = requestString.split(CHAR_ENTER); String[] firstArr = arr[0].split(CHAR_SPACE); this.method = firstArr[0]; try { this.host = arr[1].split(CHAR_HEADS_KEY_VALUE_SPLIT)[1]; if (CHAR_GET.equals(this.method)) { String urlAndParams = firstArr[1]; if (urlAndParams.contains(CHAR_URL_SPLIT)) { this.url = firstArr[1].split(CHAR_URL_SPLIT)[0]; String params = firstArr[1].split(CHAR_URL_SPLIT)[1]; String[] paramsArr = params.split(CHAR_PARAMS_SPLIT); for (String param : paramsArr) { String[] paramsKeyValue = param.split(CHAR_PARAMS_KEY_VALUE_SPLIT); this.parameters.put(paramsKeyValue[0], paramsKeyValue.length == 2 ?paramsKeyValue[1] : ""); } for (int i = 1; i< arr.length && !"".equals(arr[i]) ;i++) { String headerKeyValue = arr[i]; String[] headerKeyValues = headerKeyValue.split(CHAR_HEADS_KEY_VALUE_SPLIT); this.parameters.put(headerKeyValues[0], headerKeyValues.length == 2 ?headerKeyValues[1] : ""); } }else{ this.url = firstArr[1]; } }else if(CHAR_POST.equals(this.method)){ String[] postArr = requestString.split(CHAR_ENTER+CHAR_ENTER); if (postArr.length == 2 ) { String[] paramsArr =postArr[1].split(CHAR_PARAMS_SPLIT); for (String param : paramsArr) { String[] paramsKeyValue = param.split(CHAR_PARAMS_KEY_VALUE_SPLIT); this.parameters.put(paramsKeyValue[0], paramsKeyValue.length == 2 ?paramsKeyValue[1] : ""); } } for (int i = 1; i< postArr.length && !"".equals(postArr[i]) ;i++) { String headerKeyValue = postArr[i]; String[] headerKeyValues = headerKeyValue.split(CHAR_HEADS_KEY_VALUE_SPLIT); this.parameters.put(headerKeyValues[0], headerKeyValues.length == 2 ?headerKeyValues[1] : ""); } } } catch (Exception e) { e.printStackTrace(); } } public String getMethod() { return method; } public void setMethod(String method) { this.method = method; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public Map<String,Object> getParameters() { return parameters; } public void setParameters(Map<String,Object> parameters) { this.parameters = parameters; } public String getHost() { return host; } public void setHost(String host) { this.host = host; } public Map<String, Object> getHeaders() { return headers; } public void setHeaders(Map<String, Object> headers) { this.headers = headers; } }
public class HttpServletResponse { private SocketChannel channel; private String CHAR = "UTF-8"; private static final String ENTER = "\r\n"; private static final String SPACE = " "; public HttpServletResponse(SocketChannel channel) { this.channel = channel; this.CHAR = "UTF-8"; } private String bulidHeader(String s){ StringBuilder contextText = new StringBuilder(); contextText.append(s); StringBuilder sb = new StringBuilder(); /*通用头域begin*/ sb.append("HTTP/1.1").append(SPACE).append("200").append(SPACE).append("OK").append(ENTER); sb.append("Server:myServer").append(SPACE).append("0.0.1v").append(ENTER); sb.append("Date:Sat,"+SPACE).append(new Date()).append(ENTER); sb.append("Content-Type:text/html;charset=UTF-8").append(ENTER); sb.append("Content-Length:").append(contextText.toString().getBytes().length).append(ENTER); /*通用头域end*/ sb.append(ENTER);//空一行 sb.append(contextText);//正文部分 System.out.println(sb.toString()); return sb.toString(); } public void write(String s) { try { ByteBuffer bb2 = ByteBuffer.allocate(1024); bb2.put((bulidHeader(s)).getBytes(CHAR)); bb2.flip(); channel.write(bb2); bb2.clear(); channel.close(); } catch (IOException e) { e.printStackTrace(); } } }
public class HttpServletContext { private static Map<String,XmlServletEntity> haddlerMapping ; private HttpServletContext (){ haddlerMapping = new SaxXMLUtil().init().getHaddlerMapping(); } private static HttpServletContext instance; public static HttpServletContext getInstace(){ if (instance == null) { synchronized (HttpServletContext.class) { if (instance == null) { instance = new HttpServletContext(); } } } return instance; } public Map<String,XmlServletEntity> getHanddlerMapping(){ return haddlerMapping ; } }
public class SaxXMLUtil extends DefaultHandler{ //private Map<String,XmlServletEntity> map; private List<ServletEntity> listServlet; private List<ServletMappingEntity> listMapping; private String tagName; ServletEntity entityServlet; ServletMappingEntity entityServletMapping; private int flag = 0; public SaxXMLUtil init(){ SAXParser parser = null; try { parser = SAXParserFactory.newInstance().newSAXParser(); InputStream stream=SaxXMLUtil.class.getClassLoader().getResourceAsStream("web.xml"); //调用parse()方法 parser.parse(stream, this); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return this; } public Map<String,XmlServletEntity> getHaddlerMapping() { Map<String,XmlServletEntity> map = new HashMap<String, XmlServletEntity>(); for (ServletEntity servlet : listServlet) { XmlServletEntity entity =new XmlServletEntity(); entity.setServletName(servlet.getServletName()); entity.setServletClass(servlet.getServletClass()); String servletName = servlet.getServletName(); for (ServletMappingEntity mapping : listMapping) { if (servletName.equals(mapping.getServletName())) { entity.setServletpattern(mapping.getServletpattern()); map.put(entity.getServletName(), entity); break; } } } return map; } @Override public void startDocument() throws SAXException { super.startDocument(); listServlet = new ArrayList<ServletEntity>(); listMapping = new ArrayList<ServletMappingEntity>(); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { //super.startElement(uri, localName, qName, attributes); if(qName.equals("servlet")){ entityServlet = new ServletEntity(); this.flag = 1; } if(qName.equals("servlet-mapping")){ entityServletMapping = new ServletMappingEntity(); this.flag = 2; } this.tagName = qName; } @Override public void endElement(String uri, String localName, String qName) throws SAXException { //super.endElement(uri, localName, qName); if(qName.equals("servlet")){ listServlet.add( entityServlet); flag = 0; } if(qName.equals("servlet-mapping")){ listMapping.add( entityServletMapping); flag = 0; } this.tagName = null; } @Override public void characters(char[] ch, int start, int length) throws SAXException { //super.characters(ch, start, length); if(this.tagName!=null){ if(this.flag == 1){ String data=new String(ch,start,length); if(this.tagName.equals("servlet-name")){ this.entityServlet.setServletName(data); } if(this.tagName.equals("servlet-class")){ this.entityServlet.setServletClass(data); } }else if (this.flag == 2) { String data=new String(ch,start,length); if(this.tagName.equals("servlet-name")){ this.entityServletMapping.setServletName(data); } if(this.tagName.equals("url-pattern")){ this.entityServletMapping.setServletpattern(data); } } } } @Override public void endDocument() throws SAXException { super.endDocument(); } public static void main(String[] args) { SaxXMLUtil util = new SaxXMLUtil(); Map<String, XmlServletEntity> map = util.init().getHaddlerMapping(); for (XmlServletEntity entity : map.values()) { System.out.println(entity.getServletName() +"\r\t" + entity.getServletClass() +"\r\t" + entity.getServletpattern()); } /* secondServlet com.curiousby.baoyou.cn.showandshare.customized.tomcat.demo.SecondServlet /secondServlet firstServlet com.curiousby.baoyou.cn.showandshare.customized.tomcat.demo.FirstServlet /firstServlet */ } }
public class FirstServlet extends HttpServlet{ @Override public void doGet(HttpServletRequest reqest, HttpServletResponse response) { super.doGet(reqest, response); doPost(reqest, response); } @Override public void doPost(HttpServletRequest reqest, HttpServletResponse response) { super.doPost(reqest, response); Map<String, Object> parameters = reqest.getParameters(); response.write("{\"name\":\"baoyou\"}"); } }
public class SecondServlet extends HttpServlet{ @Override public void doGet(HttpServletRequest reqest, HttpServletResponse response) { super.doGet(reqest, response); doPost(reqest, response); } @Override public void doPost(HttpServletRequest reqest, HttpServletResponse response) { super.doPost(reqest, response); response.write("SecondServlet"); } }
<web-app> <!-- ===========================firstServlet====================== --> <servlet> <servlet-name>firstServlet</servlet-name> <servlet-class>com.curiousby.baoyou.cn.showandshare.customized.tomcat.demo.FirstServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>firstServlet</servlet-name> <url-pattern>/firstServlet</url-pattern> </servlet-mapping> <!-- ===========================firstServlet====================== --> <!-- ===========================secondServlet====================== --> <servlet> <servlet-name>secondServlet</servlet-name> <servlet-class>com.curiousby.baoyou.cn.showandshare.customized.tomcat.demo.SecondServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>secondServlet</servlet-name> <url-pattern>/secondServlet.do</url-pattern> </servlet-mapping> <!-- ===========================secondServlet====================== --> </web-app>
捐助开发者
在兴趣的驱动下,写一个免费
的东西,有欣喜,也还有汗水,希望你喜欢我的作品,同时也能支持一下。 当然,有钱捧个钱场(支持支付宝和微信 以及扣扣群),没钱捧个人场,谢谢各位。
个人主页:http://knight-black-bob.iteye.com/
谢谢您的赞助,我会做的更好!