简易版基于Java的Servlet容器实现
如上文简易版基于Java的Web服务器实现中该服务器可以处理静态页面,在上文基础上实现既可以处理静态页面和Servlet的简易服务器。
HttpServer1类
package com.vipshop.test.ext02;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.InetAddress;import java.net.ServerSocket;import java.net.Socket;import java.net.UnknownHostException;public class HttpServer1 {// shutdown commandprivate static final String SHUTDOWN_COMMAND = "/SHUTDOWN";// the shutdown command receivedprivate boolean shutdown = false;public static void main(String[] args) {HttpServer1 server = new HttpServer1();server.await();}public void await() {ServerSocket serverSocket = null;int port = 8080;try {serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));} catch (UnknownHostException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();System.exit(1);}// Loop waiting for a requestwhile(!shutdown) {Socket socket = null;InputStream input = null;OutputStream output = null;try {socket = serverSocket.accept();input = socket.getInputStream();output = socket.getOutputStream();} catch (IOException e1) {e1.printStackTrace();}// create Request object and parseRequest request = new Request(input);request.parse();// create Response objectResponse response = new Response(output);response.setRequest(request);// check if this is a request for a servlet or a static resource// a request for a servlet begings with "/servlet"if (request.getUri().startsWith("/servlet/")) {ServletProcessor1 processor = new ServletProcessor1();processor.process(request, response);} else {StaticResourceProcessor processor = new StaticResourceProcessor();processor.process(request, response);}try {// Close the socketsocket.close();// check if the previous URI is a shutdown commandshutdown = request.getUri().equals(SHUTDOWN_COMMAND);} catch (IOException e) {e.printStackTrace();System.exit(1);}}}}
处理静态资源的处理器StaticResourceProcessor
package com.vipshop.test.ext02;import java.io.IOException;public class StaticResourceProcessor {public void process(Request request, Response response) {try {response.sendStaticResource();} catch (IOException e) {e.printStackTrace();}}}
Servlet的处理器ServletProcessor
package com.vipshop.test.ext02;import java.io.IOException;import javax.servlet.Servlet;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;public class ServletProcessor1 {public void process (Request request, Response response) {String uri = request.getUri();String servletName = uri.substring(uri.lastIndexOf("/") + 1);Object myClass = null;try {myClass = Class.forName("com.vipshop.test.ext02.servlet." + servletName).newInstance();// = loader.loadClass(servletName);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}Servlet servlet = null;try {servlet = (Servlet) myClass;System.out.println(servlet);servlet.service((ServletRequest) request, (ServletResponse) response);} catch (ServletException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}}
请求类Request
package com.vipshop.test.ext02;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.UnsupportedEncodingException;import java.util.Enumeration;import java.util.Locale;import java.util.Map;import javax.servlet.RequestDispatcher;import javax.servlet.ServletInputStream;import javax.servlet.ServletRequest;public class Request implements ServletRequest {private InputStream input;private String uri;public Request(InputStream input) {this.input = input;}public String getUri() {return uri;}private String parseUri(String requestString) {int index1, index2;index1 = requestString.indexOf(' ');if (index1 != -1) {index2 = requestString.indexOf(' ', index1 + 1);if (index2 > index1) {return requestString.substring(index1 + 1, index2);}}return null;}public void parse() {// Read a set of characters from the socketStringBuffer request = new StringBuffer(2048);int i; byte[] buffer = new byte[2048];try {i = input.read(buffer);} catch (IOException e) {e.printStackTrace();i = -1;}for (int j = 0; j < i; j ++) {request.append((char) buffer[j]);}System.out.println("----------------");System.out.print(request.toString());System.out.println("----------------");uri = parseUri(request.toString());}@Overridepublic Object getAttribute(String name) {return null;}@Overridepublic Enumeration getAttributeNames() {return null;}@Overridepublic String getCharacterEncoding() {return null;}@Overridepublic int getContentLength() {return 0;}@Overridepublic String getContentType() {return null;}@Overridepublic ServletInputStream getInputStream() throws IOException {return null;}@Overridepublic String getLocalAddr() {return null;}@Overridepublic Locale getLocale() {return null;}@Overridepublic Enumeration getLocales() {return null;}@Overridepublic String getLocalName() {return null;}@Overridepublic int getLocalPort() {return 0;}@Overridepublic String getParameter(String name) {return null;}@Overridepublic Map getParameterMap() {return null;}@Overridepublic Enumeration getParameterNames() {return null;}@Overridepublic String[] getParameterValues(String name) {return null;}@Overridepublic String getProtocol() {return null;}@Overridepublic BufferedReader getReader() throws IOException {return null;}@Overridepublic String getRealPath(String path) {return null;}@Overridepublic String getRemoteAddr() {return null;}@Overridepublic String getRemoteHost() {return null;}@Overridepublic int getRemotePort() {return 0;}@Overridepublic RequestDispatcher getRequestDispatcher(String path) {return null;}@Overridepublic String getScheme() {return null;}@Overridepublic String getServerName() {return null;}@Overridepublic int getServerPort() {return 0;}@Overridepublic boolean isSecure() {return false;}@Overridepublic void removeAttribute(String name) {}@Overridepublic void setAttribute(String name, Object o) {}@Overridepublic void setCharacterEncoding(String env)throws UnsupportedEncodingException {}}
响应类类Response
package com.vipshop.test.ext02;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.io.OutputStream;import java.io.PrintWriter;import java.util.Locale;import javax.servlet.ServletOutputStream;import javax.servlet.ServletResponse;public class Response implements ServletResponse {private static final int BUFFER_SIZE = 1024;private Request request;private OutputStream output;private PrintWriter writer;public Response(OutputStream output) {this.output = output;}public void setRequest(Request request) {this.request = request;}/** * This method is used to save a static page * @throws IOException */public void sendStaticResource() throws IOException {byte[] bytes = new byte[BUFFER_SIZE];FileInputStream fis = null;try {File file = new File(Constants.WEB_ROOT, request.getUri());fis = new FileInputStream(file);int ch = fis.read(bytes, 0, BUFFER_SIZE);while(ch != -1) {output.write(bytes, 0, BUFFER_SIZE);ch = fis.read(bytes, 0, BUFFER_SIZE);}} catch (FileNotFoundException e) {String errorMessage = "HTTP/1.1 404 File Not Found\r\n"+ "Content-Type: text/html\r\n"+ "\r\n" + "<h1>File Not Found</h1>";output.write(errorMessage.getBytes());} finally {if (fis != null) {fis.close();this.flushBuffer();this.getOutputStream().close();this.getWriter().close();}}}@Overridepublic void flushBuffer() throws IOException {}@Overridepublic int getBufferSize() {return 0;}@Overridepublic String getCharacterEncoding() {return null;}@Overridepublic String getContentType() {return null;}@Overridepublic Locale getLocale() {return null;}@Overridepublic ServletOutputStream getOutputStream() throws IOException {return null;}@Overridepublic PrintWriter getWriter() throws IOException {return new PrintWriter(this.output, true);}@Overridepublic boolean isCommitted() {return false;}@Overridepublic void reset() {}@Overridepublic void resetBuffer() {}@Overridepublic void setBufferSize(int size) {}@Overridepublic void setCharacterEncoding(String charset) {}@Overridepublic void setContentLength(int len) {}@Overridepublic void setContentType(String type) {}@Overridepublic void setLocale(Locale loc) {}}
上述简易版可以处理Servlet的容器已经实现了考虑到HttpServer1调度StaticResourceProcessor类和ServletProcessor1类,Processor直接调用Response和Request,耦合度较高。
在此引入装饰器模式
RequestFacade类
package com.vipshop.test.ext02;import java.io.IOException;import java.io.PrintWriter;import java.util.Locale;import javax.servlet.ServletOutputStream;import javax.servlet.ServletResponse;public class ResponseFacade implements ServletResponse {private ServletResponse response;public ResponseFacade(Response response) {this.response = response;}@Overridepublic void flushBuffer() throws IOException {response.flushBuffer();}@Overridepublic int getBufferSize() {return response.getBufferSize();}@Overridepublic String getCharacterEncoding() {return response.getCharacterEncoding();}@Overridepublic String getContentType() {return response.getContentType();}@Overridepublic Locale getLocale() {return response.getLocale();}@Overridepublic ServletOutputStream getOutputStream() throws IOException {return response.getOutputStream();}@Overridepublic PrintWriter getWriter() throws IOException {return response.getWriter();}@Overridepublic boolean isCommitted() {return response.isCommitted();}@Overridepublic void reset() {response.reset();}@Overridepublic void resetBuffer() {response.resetBuffer();}@Overridepublic void setBufferSize(int size) {response.setBufferSize(size);}@Overridepublic void setCharacterEncoding(String charset) {response.setCharacterEncoding(charset);}@Overridepublic void setContentLength(int len) {response.setContentLength(len);}@Overridepublic void setContentType(String type) {response.setContentType(type);}@Overridepublic void setLocale(Locale loc) {response.setLocale(loc);}}
RequestFacade类
package com.vipshop.test.ext02;import java.io.BufferedReader;import java.io.IOException;import java.io.UnsupportedEncodingException;import java.util.Enumeration;import java.util.Locale;import java.util.Map;import javax.servlet.RequestDispatcher;import javax.servlet.ServletInputStream;import javax.servlet.ServletRequest;public class RequestFacade implements ServletRequest {private ServletRequest request = null;public RequestFacade(Request request) {this.request = request;}@Overridepublic Object getAttribute(String name) {return request.getAttribute(name);}@Overridepublic Enumeration getAttributeNames() {return request.getAttributeNames();}@Overridepublic String getCharacterEncoding() {return request.getCharacterEncoding();}@Overridepublic int getContentLength() {return request.getContentLength();}@Overridepublic String getContentType() {return request.getCharacterEncoding();}@Overridepublic ServletInputStream getInputStream() throws IOException {return request.getInputStream();}@Overridepublic String getLocalAddr() {return request.getLocalAddr();}@Overridepublic Locale getLocale() {return request.getLocale();}@Overridepublic Enumeration getLocales() {return request.getLocales();}@Overridepublic String getLocalName() {return request.getLocalName();}@Overridepublic int getLocalPort() {return request.getLocalPort();}@Overridepublic String getParameter(String name) {return request.getParameter(name);}@Overridepublic Map getParameterMap() {return request.getParameterMap();}@Overridepublic Enumeration getParameterNames() {return request.getAttributeNames();}@Overridepublic String[] getParameterValues(String name) {return request.getParameterValues(name);}@Overridepublic String getProtocol() {return request.getProtocol();}@Overridepublic BufferedReader getReader() throws IOException {return request.getReader();}@Overridepublic String getRealPath(String path) {return request.getRealPath(path);}@Overridepublic String getRemoteAddr() {return request.getRemoteAddr();}@Overridepublic String getRemoteHost() {return request.getRemoteHost();}@Overridepublic int getRemotePort() {return request.getRemotePort();}@Overridepublic RequestDispatcher getRequestDispatcher(String path) {return request.getRequestDispatcher(path);}@Overridepublic String getScheme() {return request.getScheme();}@Overridepublic String getServerName() {return request.getServerName();}@Overridepublic int getServerPort() {return request.getServerPort();}@Overridepublic boolean isSecure() {return request.isSecure();}@Overridepublic void removeAttribute(String name) {request.removeAttribute(name);}@Overridepublic void setAttribute(String name, Object o) {request.setAttribute(name, o);}@Overridepublic void setCharacterEncoding(String env)throws UnsupportedEncodingException {request.setCharacterEncoding(env);}}
Servlet处理器只和RequestFacade类和ResponseFacade类通话
package com.vipshop.test.ext02;import java.io.IOException;import javax.servlet.Servlet;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;public class ServletProcessor2 {public void process (Request request, Response response) {String uri = request.getUri();String servletName = uri.substring(uri.lastIndexOf("/") + 1);Object myClass = null;try {myClass = Class.forName("com.vipshop.test.ext02.servlet." + servletName).newInstance();// = loader.loadClass(servletName);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}Servlet servlet = null;RequestFacade requestFacade = new RequestFacade(request);ResponseFacade responseFacade = new ResponseFacade(response);try {servlet = (Servlet) myClass;System.out.println(servlet);servlet.service((ServletRequest) requestFacade, (ServletResponse) responseFacade);} catch (ServletException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}}
至此简易版Servlet容器已经实现