这次我们Tomcat 的改动是 指责分离,同时引入一个Wrapper封装
我们的Processor 是负责处理处理请求的任务
我们的Connector 是负责通信的
详细代码如下
public class JxdHttpConnector implements Runnable { int minProcessors = 3; int maxProcessors = 10; int curProcessors = 0; //存放多个processor的池子 Deque<JxdHttpProcessor> processorDeque = new ArrayDeque<>(); private ServletContainer container; //sessions map存放session public static Map<String, HttpSession> sessions = new ConcurrentHashMap<>(); //创建新的session public static JxdSession createSession() { JxdSession session = new JxdSession(); session.setValid(true); session.setCreationTime(System.currentTimeMillis()); String sessionId = generateSessionId(); session.setId(sessionId); sessions.put(sessionId, session); return (session); } /** * 生成随机数方法 * @return */ protected static synchronized String generateSessionId() { Random random = new Random(); long seed = System.currentTimeMillis(); random.setSeed(seed); byte bytes[] = new byte[16]; random.nextBytes(bytes); StringBuffer result = new StringBuffer(); for (int i = 0; i < bytes.length; i++) { byte b1 = (byte) ((bytes[i] & 0xf0) >> 4); byte b2 = (byte) (bytes[i] & 0x0f); if (b1 < 10) result.append((char) ('0' + b1)); else result.append((char) ('A' + (b1 - 10))); if (b2 < 10) result.append((char) ('0' + b2)); else result.append((char) ('A' + (b2 - 10))); } return (result.toString()); } @Override public void run() { ServerSocket serverSocket = null; int port = 8080; try { serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1")); } catch (IOException e) { e.printStackTrace(); System.exit(1); } //初始化池子 最开始三个 initProcessorDeque(); while (true) { Socket socket = null; try { //这是单线程 一个请求一个请求获取socket socket = serverSocket.accept(); //得到一个新的processor,这个processor从池中获取(池中有可能新建) JxdHttpProcessor processor = createProcessor(); if (processor == null) { socket.close(); continue; } processor.assign(socket); } catch (Exception e) { e.printStackTrace(); } } } public void start() { Thread thread = new Thread(this); thread.start(); } //从池子中获取一个processor,如果池子为空且小于最大限制,则新建一个 private JxdHttpProcessor createProcessor() { synchronized (processorDeque) { if (processorDeque.size() > 0) { return processorDeque.pop(); } if (curProcessors < maxProcessors) { return newProcessor(); } else { return null; } } } private void initProcessorDeque() { for (int i = 0; i < minProcessors; i++) { JxdHttpProcessor processor = new JxdHttpProcessor(this); processor.start(); processorDeque.push(processor); } curProcessors = minProcessors; } private JxdHttpProcessor newProcessor() { JxdHttpProcessor jxdHttpProcessor = new JxdHttpProcessor(this); jxdHttpProcessor.start(); processorDeque.push(jxdHttpProcessor); curProcessors++; return processorDeque.pop(); } public void recycle(JxdHttpProcessor processor) { processorDeque.push(processor); } public ServletContainer getContainer() { return container; } public void setContainer(ServletContainer container) { this.container = container; } }
public class JxdHttpProcessor implements Runnable { boolean available = false; Socket socket; JxdHttpConnector connector; private int serverPort = 0; private boolean keepAlive = false; private boolean http11 = true; public JxdHttpProcessor(JxdHttpConnector connector) { this.connector = connector; } private void process(Socket socket) { //服务器循环等待请求并处理 try { Thread.sleep(3000); } catch (InterruptedException e1) { e1.printStackTrace(); } InputStream input = null; OutputStream output = null; // create Request object and parse JxdRequest request = new JxdRequest(); try { output = socket.getOutputStream(); keepAlive = true; //先关掉keepAlive 目前 为了方便测试 // while (keepAlive) { request.parse(socket); // create Response object JxdResponse response = new JxdResponse(output); response.setRequest(request); request.setResponse(response); //handle session if (request.getSessionId() == null || request.getSessionId().equals("")) { request.getSession(true); } response.setCharacterEncoding("UTF-8"); response.addHeader(DefaultHeaders.CONTENT_TYPE_NAME, "text/html;charset=UTF-8"); response.sendHeaders();//发送响应头 //这段代码是测试用,可以获取的 请求参数 支持get 和post Map<String, String[]> map = request.getParameterMap(); if (request.getUri().startsWith("/servlet/")) { //加载动态资源 JxdServletProcessor jxdServletProcessor = new JxdServletProcessor(connector); jxdServletProcessor.process(request, response); } else { //加载静态资源 StaticResourceProcessor staticResourceProcessor = new StaticResourceProcessor(); staticResourceProcessor.process(request, response); } response.finishResponse(); System.out.println("response header connection------"+response.getHeader("Connection")); if ("close".equals(response.getHeader("Connection"))) { keepAlive = false; } // } //因为是多线程所以只能交给httpProcessor 来关闭 socket.close(); } catch (Exception ea) { ea.printStackTrace(); } } @Override public void run() { while (true) { // 等待socket分配过来 Socket socket = await(); if (socket == null) continue; // 处理请求 process(socket); // 回收processor connector.recycle(this); } } public void start() { Thread thread = new Thread(this); thread.start(); } private synchronized Socket await() { // 等待connector提供一个新的socket while (!available) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 获得这个新的Socket Socket socket = this.socket; //设置标志为false available = false; //通知另外的线程 notifyAll(); return (socket); } public synchronized void assign(Socket socket) { // 等待connector提供一个新的socket while (available) { try { wait(); } catch (InterruptedException e) { } } // 获取到这个新的Socket this.socket = socket; // 把标志设置回去 available = true; //通知另外的线程 notifyAll(); } }
同时引入一个Wapper
/** * ServletContainer 主要用servletClsMap,servletInstanceMap 两个 * map 管理Servlet */ public class ServletWrapper { private Servlet instance = null; private String servletClass; private ClassLoader loader; private String name; protected ServletContainer container = null; public ServletWrapper(String servletClass, ServletContainer container) { this.container = container; this.servletClass = servletClass; try { loadServlet(); } catch (ServletException e) { e.printStackTrace(); } } public ClassLoader getLoader() { if (loader != null) return loader; return container.getLoader(); } public Servlet getServlet(){ return this.instance; } public Servlet loadServlet() throws ServletException { if (instance!=null) return instance; Servlet servlet = null; String actualClass = servletClass; if (actualClass == null) { throw new ServletException("servlet class has not been specified"); } ClassLoader classLoader = getLoader(); Class classClass = null; try { if (classLoader!=null) { classClass = classLoader.loadClass(actualClass); } } catch (ClassNotFoundException e) { throw new ServletException("Servlet class not found"); } try { servlet = (Servlet) classClass.newInstance(); } catch (Throwable e) { throw new ServletException("Failed to instantiate servlet"); } try { servlet.init(null); } catch (Throwable f) { throw new ServletException("Failed initialize servlet."); } instance =servlet; return servlet; } public void invoke(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { if (instance != null) { instance.service(request, response); } } }
引入一个Servlet 容器 ,里边是一个map 用来管理 Servlet 不必每次都要创建
/** * ServletContainer 主要用servletClsMap,servletInstanceMap 两个 * map 管理Servlet */ public class ServletContainer { JxdHttpConnector connector = null; ClassLoader loader = null; //包含servlet类和实例的map Map<String, String> servletClsMap = new ConcurrentHashMap<>(); //servletName - Map<String, ServletWrapper> servletInstanceMap = new ConcurrentHashMap<>();//servletN public ServletContainer() { try { // create a URLClassLoader URL[] urls = new URL[1]; URLStreamHandler streamHandler = null; File classPath = new File(JxdHttpServer.WEB_ROOT); String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString(); urls[0] = new URL(null, repository, streamHandler); loader = new URLClassLoader(urls); } catch (IOException e) { System.out.println(e.toString()); } } public String getInfo() { return null; } public ClassLoader getLoader() { return this.loader; } public void setLoader(ClassLoader loader) { this.loader = loader; } public JxdHttpConnector getConnector() { return connector; } public void setConnector(JxdHttpConnector connector) { this.connector = connector; } public String getName() { return null; } public void setName(String name) { } //invoke方法用于从map中找到相关的servlet,然后调用 public void invoke(JxdRequest request, JxdResponse response) throws IOException, ServletException { ServletWrapper servletWrapper = null; String uri = request.getUri(); //首先根据uri最后一个/号来定位,后面的字符串认为是servlet名字 String servletName = uri.substring(uri.lastIndexOf("/") + 1); String servletClassName = servletName; servletWrapper = servletInstanceMap.get(servletName); //如果容器内没有这个servlet,先要load类,创建新实例 if (servletWrapper == null) { servletWrapper = new ServletWrapper(servletClassName, this); this.servletClsMap.put(servletName, servletClassName); this.servletInstanceMap.put(servletName, servletWrapper); } try { HttpRequestFacade requestFacade = new HttpRequestFacade(request); HttpResponseFacade responseFacade = new HttpResponseFacade(response); System.out.println("Call service()"); //让servletWrapper去执行servlet servletWrapper.invoke(requestFacade,responseFacade); } catch (Exception e) { System.out.println(e.toString()); } catch (Throwable e) { System.out.println(e.toString()); } } }
JxdHttpServer 我们的启动类 也发发生了变化
public class JxdHttpServer { public static final String WEB_ROOT = System.getProperty("user.dir"); public static final String FILE_ROOT = "D:\\"; public static void main(String[] args) { JxdHttpConnector connector = new JxdHttpConnector(); ServletContainer container = new ServletContainer(); connector.setContainer(container); container.setConnector(connector); connector.start(); } }