首页 > 代码库 > 《How Tomcat Works》读书笔记(二)
《How Tomcat Works》读书笔记(二)
《How Tomcat Works》读书笔记(二)
这是《How Tomcat Works》第一二章的读书笔记。第一张主要写了一个静态资源处理的web服务器,第二章加了对servlet的处理。
1. 概述
1.1 架构
- HttpServer:表示Http服务器,与客户端通信,处理Http请求。
- StaticResourceProcessor:对静态资源请求进行处理。
- ServletProcessor:对Servlet资源请求进行处理。
- Request:表示Http请求,实现了ServletRequest接口。
- Response:表示Http响应,实现了ServletResponse接口。
- RequestFacade/ResponseFacade:Request/Response的门面类。
- PrimitiveServlet:表示一个Servlet类。
1.2 一些代码
HttpServer处理逻辑:
1 // check if this is a request for a servlet or 2 // a static resource 3 // a request for a servlet begins with "/servlet/" 4 if (request.getUri().startsWith("/servlet/")) { 5 ServletProcessor1 processor = new ServletProcessor1(); 6 processor.process(request, response); 7 } 8 else { 9 StaticResoureProcessor processor = new StaticResourceProcessor(); 10 processor.process(request, response); 11 }
ServletProcessor中通过类加载器把.class文件动态的加载为Servlet对象:
1 public void process(Request request, Response response) { 2 String uri = request.getUri(); 3 String servletName = uri.substring(uri.lastIndexOf("/") + 1); 4 URLClassLoader loader = null; 5 try { 6 // create a URLClassLoader 7 URL[] urls = new URL[1]; 8 URLStreamHandler streamHandler = null; 9 File classPath = new File(Constants.WEB_ROOT); 10 // the forming of repository is taken from the 11 // createClassLoader method in 12 // org.apache.catalina.startup.ClassLoaderFactory 13 String repository =(new URL("file", null, 14 classPath.getCanonicalPath() + File.separator)).toString() ; 15 // the code for forming the URL is taken from 16 // the addRepository method in 17 // org.apache.catalina.loader.StandardClassLoader. 18 urls[0] = new URL(null, repository, streamHandler); 19 loader = new URLClassLoader(urls); 20 } catch (IOException e) { 21 } 22 Class myClass = null; 23 try { 24 myClass = loader.loadClass(servletName); 25 } catch (ClassNotFoundException e) { 26 } 27 Servlet servlet = null; 28 try { 29 servlet = (Servlet) myClass.newInstance(); 30 // 使用门面设计模式 31 RequestFacade rquestFacade = new RequestFacade(request); 32 ResponseFacade responseFacade = new RespondeFacade(response); 33 // 交由Servlet进行处理 34 servlet.service(requestFacade, responseFacade); 35 } 36 }
1.3 设计模式
在这里使用了门面的设计模式,目的是安全性。在StaticResourceProcessor.processor()方法中会把Request、Response对象传给Servelt进行处理,在后面程序猿处理Servlet请求时就可以把ServletRequest向下转型为Request对象,然后使用不该在此使用的方法,如:parse()方法。所以,在这里使用了门面设计模式。
ResponseFacade类:
1 public class ResponseFacade implements ServletResponse { 2 private ServletResponse servletResponse = null; 3 4 // 通过构造方法传入真正的Response,然后向上转型为ServletResponse 5 public ResponseFacade(Response response) { 6 this.servletResponse = response; 7 } 8 /** 9 * 后面都是实现ServlerResponse接口要实现的方法,就不写完了。 10 */ 11 @Override 12 public String getCharacterEncoding() { 13 return servletResponse.getCharacterEncoding(); 14 } 15 @Override 16 public String getContentType() { 17 return servletResponse.getContentType(); 18 }
2. 注意
2.1 HTTP协议
HTTP协议是应用层协议,它基于TCP/IP协议进行传输数据。在客户端与web服务器解析数据时,必须有相关的头部数据。所以web服务器给客户端发出响应,该响应必须加入头部数据。自己在写该代码时,就忘了加头部数据,出个bug,解决了一段时间才发现。
PrimitiveServlet的service()方法:
1 public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { 2 String header = "HTTP/1.1 200 OK\r\n" 3 + "Content-Type: text/html;charset=UTF-8\r\n" 4 + "\r\n"; 5 String content = "<html>\r\n" 6 + "<head>" 7 + "</head>" 8 + "<body>" 9 + "Primitive Servlet" 10 + "</body>" 11 + "</html>"; 12 PrintWriter writer = res.getWriter(); 13 writer.write(header); 14 writer.write(content); 15 writer.flush(); 16 writer.close(); 17 }
我们平时使用Servlet开发时,直接继承HttpServlet,容器会自动的加上HTTP Response相关信息。
2.2 MIME类型
HTTP Respose header中有一个ContentType字段,它要求告诉客户端该Response正文的内容MIME类型,我们可以通过下面的API获得某一个文件的MIME类型。
String mimeType = URLConnection.getFileNameMap().getContentTypeFor(fileName)
2.2 .class文件
该系统使用到了URLClassLoader加载Class对象,ClassLoader把字节码(.class文件)加载为Class对象,所以需要编译好的.class文件。在Idea中Project中有个out目录,其中放的就是编译好的.class文件(只要你使用Idea运行过的.java文件)。
3. 代码
与原书逻辑基本一致,由于自己加入了多线程技术,所以新增了Servlet容器(使用了Map),并且该容器一开始就加载所有的Servlet。
HttpServer:
1 package note1; 2 3 import java.io.IOException; 4 import java.net.ServerSocket; 5 import java.net.Socket; 6 import java.util.concurrent.ExecutorService; 7 import java.util.concurrent.Executors; 8 9 /** 10 * Created by kanyuxia on 2017/4/24. 11 * HttpServer是模拟HTTP服务器:接受HTTP请求,响应静态资源或者Servlet资源 12 */ 13 public class HttpServer { 14 /** 15 * HttpServer端口号 16 */ 17 public static final int PORT = 10086; 18 /** 19 * Http静态文件根目录 20 */ 21 public static final String STATIC_RESOURCE_ROOT = "E:/java/HttpServer/staticresource"; 22 /** 23 * Http中Servlet文件根目录 24 */ 25 public static final String SERVLET_ROOT = "E:/java/HttpServer/servlet"; 26 /** 27 * 线程池 28 */ 29 private ExecutorService executorService; 30 /** 31 * 线程池大小 32 */ 33 public static final int THREAD_POOL_SIZE = 50; 34 35 HttpServer() { 36 executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE); 37 } 38 39 /** 40 * 启动HttpServer服务器 41 * 使用了try-with-resource: since jdk1.7 42 */ 43 public void start() { 44 // 创建ServerSocket 45 try (ServerSocket serverSocket = new ServerSocket(PORT)) { 46 while (true) { 47 // 客户端连接 48 Socket socket = serverSocket.accept(); 49 // 使用线程池处理该socket 50 ServerHandle serverHandle = new ServerHandle(socket); 51 executorService.execute(serverHandle); 52 } 53 } catch (IOException e) { 54 System.out.println(e); 55 } 56 } 57 }
Request:
1 package note1; 2 3 import javax.servlet.*; 4 import java.io.*; 5 import java.util.Enumeration; 6 import java.util.Locale; 7 import java.util.Map; 8 9 /** 10 * Created by kanyuxia on 2017/4/24 11 * Request类:实现了ServletRequest接口,如果HTTP请求是Servlet,则服务器创建ServletRequest和ServletResponse对象, 12 * 并传入Servlet的service()方法 13 */ 14 public class Request implements ServletRequest { 15 private final InputStream inputStream; 16 17 private String url; 18 19 public Request(InputStream inputStream) { 20 this.inputStream = inputStream; 21 } 22 23 public String getUrl() { 24 return url; 25 } 26 27 /** 28 * 解析请求URL 29 */ 30 public void parse() { 31 BufferedInputStream in = new BufferedInputStream(inputStream); 32 StringBuilder result = new StringBuilder(1024); 33 byte[] buffer = new byte[1024]; 34 int readNum = 0; 35 try { 36 readNum = in.read(buffer); 37 } catch (IOException e) { 38 e.printStackTrace(); 39 } 40 for (int i = 0; i < readNum; i++) { 41 result.append((char) buffer[i]); 42 } 43 // 解析URL 44 int start = result.toString().indexOf(" ") + 1; 45 int end = result.toString().indexOf(" ", start); 46 this.url = result.toString().substring(start, end); 47 } 48 49 50 @Override 51 public Object getAttribute(String name) { 52 return null; 53 } 54 55 @Override 56 public Enumeration<String> getAttributeNames() { 57 return null; 58 } 59 60 @Override 61 public String getCharacterEncoding() { 62 return null; 63 } 64 65 @Override 66 public void setCharacterEncoding(String env) throws UnsupportedEncodingException { 67 68 } 69 70 @Override 71 public int getContentLength() { 72 return 0; 73 } 74 75 @Override 76 public long getContentLengthLong() { 77 return 0; 78 } 79 80 @Override 81 public String getContentType() { 82 return null; 83 } 84 85 @Override 86 public ServletInputStream getInputStream() throws IOException { 87 return null; 88 } 89 90 @Override 91 public String getParameter(String name) { 92 return null; 93 } 94 95 @Override 96 public Enumeration<String> getParameterNames() { 97 return null; 98 } 99 100 @Override 101 public String[] getParameterValues(String name) { 102 return new String[0]; 103 } 104 105 @Override 106 public Map<String, String[]> getParameterMap() { 107 return null; 108 } 109 110 @Override 111 public String getProtocol() { 112 return null; 113 } 114 115 @Override 116 public String getScheme() { 117 return null; 118 } 119 120 @Override 121 public String getServerName() { 122 return null; 123 } 124 125 @Override 126 public int getServerPort() { 127 return 0; 128 } 129 130 @Override 131 public BufferedReader getReader() throws IOException { 132 return null; 133 } 134 135 @Override 136 public String getRemoteAddr() { 137 return null; 138 } 139 140 @Override 141 public String getRemoteHost() { 142 return null; 143 } 144 145 @Override 146 public void setAttribute(String name, Object o) { 147 148 } 149 150 @Override 151 public void removeAttribute(String name) { 152 153 } 154 155 @Override 156 public Locale getLocale() { 157 return null; 158 } 159 160 @Override 161 public Enumeration<Locale> getLocales() { 162 return null; 163 } 164 165 @Override 166 public boolean isSecure() { 167 return false; 168 } 169 170 @Override 171 public RequestDispatcher getRequestDispatcher(String path) { 172 return null; 173 } 174 175 @Override 176 public String getRealPath(String path) { 177 return null; 178 } 179 180 @Override 181 public int getRemotePort() { 182 return 0; 183 } 184 185 @Override 186 public String getLocalName() { 187 return null; 188 } 189 190 @Override 191 public String getLocalAddr() { 192 return null; 193 } 194 195 @Override 196 public int getLocalPort() { 197 return 0; 198 } 199 200 @Override 201 public ServletContext getServletContext() { 202 return null; 203 } 204 205 @Override 206 public AsyncContext startAsync() throws IllegalStateException { 207 return null; 208 } 209 210 @Override 211 public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException { 212 return null; 213 } 214 215 @Override 216 public boolean isAsyncStarted() { 217 return false; 218 } 219 220 @Override 221 public boolean isAsyncSupported() { 222 return false; 223 } 224 225 @Override 226 public AsyncContext getAsyncContext() { 227 return null; 228 } 229 230 @Override 231 public DispatcherType getDispatcherType() { 232 return null; 233 } 234 }
Response:
1 package note1; 2 3 import javax.servlet.ServletOutputStream; 4 import javax.servlet.ServletResponse; 5 import java.io.*; 6 import java.net.URLConnection; 7 import java.util.Locale; 8 9 /** 10 * Created by kanyuxia on 2017/4/24. 11 */ 12 public class Response implements ServletResponse { 13 private final Request request; 14 15 private final OutputStream outputStream; 16 17 public Response(Request request, OutputStream outputStream) { 18 this.request = request; 19 this.outputStream = outputStream; 20 } 21 22 /** 23 * 发送静态资源方法 24 * @throws IOException 25 */ 26 public void sendStaticResource() throws IOException { 27 BufferedOutputStream out = new BufferedOutputStream(outputStream); 28 //请求的本地静态文件地址 29 File file = new File(HttpServer.STATIC_RESOURCE_ROOT + request.getUrl()); 30 // 文件存在 31 if (file.exists()) { 32 String mimeType = URLConnection.getFileNameMap().getContentTypeFor(file.getName()); 33 String header = "HTTP/1.1 200 OK\r\n" 34 + "Content-Length: " + file.length() + "\r\n" 35 + "Content-Type: " + mimeType + "; charset=UTF-8\r\n" 36 + "\r\n"; 37 // 发送header 38 out.write(header.getBytes()); 39 out.flush(); 40 // 发送content 41 byte[] buffer = new byte[1024]; 42 try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(file))) { 43 for (int b = in.read(buffer); b != -1; b = in.read(buffer)) { 44 out.write(buffer, 0, b); 45 out.flush(); 46 } 47 } catch (IOException e) { 48 System.out.println(); 49 } 50 // 关闭流 51 try { 52 out.close(); 53 } catch (IOException e) { 54 System.out.println(); 55 } 56 return; 57 } 58 // 文件不存在 59 sendNotFound(); 60 } 61 62 public void sendNotFound() { 63 BufferedOutputStream out = new BufferedOutputStream(outputStream); 64 // 文件不存在 65 String header = "HTTP/1.1 404 NOT FOUND\r\n" 66 + "\r\n"; 67 String content = "<html>\r\n" + 68 "<head>" + 69 "</head>" + 70 "<body>" + 71 "File Not Found" + 72 "</body>" + 73 "</html>"; 74 // 发送数据 75 try { 76 out.write(header.getBytes()); 77 out.write(content.getBytes()); 78 out.flush(); 79 } catch (IOException e) { 80 System.out.println(e); 81 } finally { 82 // 关闭流 83 try { 84 out.close(); 85 } catch (IOException e) { 86 System.out.println(e); 87 } 88 } 89 } 90 91 @Override 92 public String getCharacterEncoding() { 93 return null; 94 } 95 96 @Override 97 public String getContentType() { 98 return null; 99 } 100 101 @Override 102 public ServletOutputStream getOutputStream() throws IOException { 103 return null; 104 } 105 106 @Override 107 public PrintWriter getWriter() throws IOException { 108 return new PrintWriter(outputStream); 109 } 110 111 @Override 112 public void setCharacterEncoding(String charset) { 113 114 } 115 116 @Override 117 public void setContentLength(int len) { 118 119 } 120 121 @Override 122 public void setContentLengthLong(long len) { 123 124 } 125 126 @Override 127 public void setContentType(String type) { 128 129 } 130 131 @Override 132 public void setBufferSize(int size) { 133 134 } 135 136 @Override 137 public int getBufferSize() { 138 return 0; 139 } 140 141 @Override 142 public void flushBuffer() throws IOException { 143 144 } 145 146 @Override 147 public void resetBuffer() { 148 149 } 150 151 @Override 152 public boolean isCommitted() { 153 return false; 154 } 155 156 @Override 157 public void reset() { 158 159 } 160 161 @Override 162 public void setLocale(Locale loc) { 163 164 } 165 166 @Override 167 public Locale getLocale() { 168 return null; 169 } 170 }
RequestFacade与ResponseFacade:
1 package note1; 2 3 import javax.servlet.*; 4 import java.io.BufferedReader; 5 import java.io.IOException; 6 import java.io.UnsupportedEncodingException; 7 import java.util.Enumeration; 8 import java.util.Locale; 9 import java.util.Map; 10 11 /** 12 * Created by kanyuxia on 2017/4/24. 13 */ 14 public class RequestFacade implements ServletRequest { 15 private final ServletRequest servletRequest; 16 17 RequestFacade(Request request) { 18 this.servletRequest = request; 19 } 20 @Override 21 public Object getAttribute(String name) { 22 return servletRequest.getAttribute(name); 23 } 24 25 @Override 26 public Enumeration<String> getAttributeNames() { 27 return servletRequest.getAttributeNames(); 28 } 29 30 @Override 31 public String getCharacterEncoding() { 32 return servletRequest.getCharacterEncoding(); 33 } 34 35 @Override 36 public void setCharacterEncoding(String env) throws UnsupportedEncodingException { 37 servletRequest.setCharacterEncoding(env); 38 } 39 40 @Override 41 public int getContentLength() { 42 return servletRequest.getContentLength(); 43 } 44 45 @Override 46 public long getContentLengthLong() { 47 return servletRequest.getContentLengthLong(); 48 } 49 50 @Override 51 public String getContentType() { 52 return servletRequest.getContentType(); 53 } 54 55 @Override 56 public ServletInputStream getInputStream() throws IOException { 57 return servletRequest.getInputStream(); 58 } 59 60 @Override 61 public String getParameter(String name) { 62 return servletRequest.getParameter(name); 63 } 64 65 @Override 66 public Enumeration<String> getParameterNames() { 67 return servletRequest.getParameterNames(); 68 } 69 70 @Override 71 public String[] getParameterValues(String name) { 72 return servletRequest.getParameterValues(name); 73 } 74 75 @Override 76 public Map<String, String[]> getParameterMap() { 77 return servletRequest.getParameterMap(); 78 } 79 80 @Override 81 public String getProtocol() { 82 return servletRequest.getProtocol(); 83 } 84 85 @Override 86 public String getScheme() { 87 return servletRequest.getScheme(); 88 } 89 90 @Override 91 public String getServerName() { 92 return servletRequest.getServerName(); 93 } 94 95 @Override 96 public int getServerPort() { 97 return servletRequest.getServerPort(); 98 } 99 100 @Override 101 public BufferedReader getReader() throws IOException { 102 return servletRequest.getReader(); 103 } 104 105 @Override 106 public String getRemoteAddr() { 107 return servletRequest.getRemoteAddr(); 108 } 109 110 @Override 111 public String getRemoteHost() { 112 return servletRequest.getRemoteHost(); 113 } 114 115 @Override 116 public void setAttribute(String name, Object o) { 117 servletRequest.setAttribute(name, o); 118 } 119 120 @Override 121 public void removeAttribute(String name) { 122 servletRequest.removeAttribute(name); 123 } 124 125 @Override 126 public Locale getLocale() { 127 return servletRequest.getLocale(); 128 } 129 130 @Override 131 public Enumeration<Locale> getLocales() { 132 return servletRequest.getLocales(); 133 } 134 135 @Override 136 public boolean isSecure() { 137 return servletRequest.isSecure(); 138 } 139 140 @Override 141 public RequestDispatcher getRequestDispatcher(String path) { 142 return servletRequest.getRequestDispatcher(path); 143 } 144 145 @Override 146 public String getRealPath(String path) { 147 return servletRequest.getRealPath(path); 148 } 149 150 @Override 151 public int getRemotePort() { 152 return servletRequest.getRemotePort(); 153 } 154 155 @Override 156 public String getLocalName() { 157 return servletRequest.getLocalName(); 158 } 159 160 @Override 161 public String getLocalAddr() { 162 return servletRequest.getLocalAddr(); 163 } 164 165 @Override 166 public int getLocalPort() { 167 return servletRequest.getLocalPort(); 168 } 169 170 @Override 171 public ServletContext getServletContext() { 172 return servletRequest.getServletContext(); 173 } 174 175 @Override 176 public AsyncContext startAsync() throws IllegalStateException { 177 return servletRequest.startAsync(); 178 } 179 180 @Override 181 public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException { 182 return servletRequest.startAsync(servletRequest, servletResponse); 183 } 184 185 @Override 186 public boolean isAsyncStarted() { 187 return servletRequest.isAsyncStarted(); 188 } 189 190 @Override 191 public boolean isAsyncSupported() { 192 return servletRequest.isAsyncSupported(); 193 } 194 195 @Override 196 public AsyncContext getAsyncContext() { 197 return servletRequest.getAsyncContext(); 198 } 199 200 @Override 201 public DispatcherType getDispatcherType() { 202 return servletRequest.getDispatcherType(); 203 } 204 } 205 206 package note1; 207 208 import javax.servlet.ServletOutputStream; 209 import javax.servlet.ServletResponse; 210 import java.io.IOException; 211 import java.io.PrintWriter; 212 import java.util.Locale; 213 214 /** 215 * Created by kanyuxia on 2017/4/24. 216 */ 217 public class ResponseFacade implements ServletResponse { 218 private final ServletResponse servletResponse; 219 220 ResponseFacade(Response response) { 221 this.servletResponse = response; 222 } 223 224 @Override 225 public String getCharacterEncoding() { 226 return servletResponse.getCharacterEncoding(); 227 } 228 229 @Override 230 public String getContentType() { 231 return servletResponse.getContentType(); 232 } 233 234 @Override 235 public ServletOutputStream getOutputStream() throws IOException { 236 return servletResponse.getOutputStream(); 237 } 238 239 @Override 240 public PrintWriter getWriter() throws IOException { 241 return servletResponse.getWriter(); 242 } 243 244 @Override 245 public void setCharacterEncoding(String charset) { 246 servletResponse.setCharacterEncoding(charset); 247 } 248 249 @Override 250 public void setContentLength(int len) { 251 servletResponse.setContentLength(len); 252 } 253 254 @Override 255 public void setContentLengthLong(long len) { 256 servletResponse.setContentLengthLong(len); 257 } 258 259 @Override 260 public void setContentType(String type) { 261 servletResponse.setContentType(type); 262 } 263 264 @Override 265 public void setBufferSize(int size) { 266 servletResponse.setBufferSize(size); 267 } 268 269 @Override 270 public int getBufferSize() { 271 return servletResponse.getBufferSize(); 272 } 273 274 @Override 275 public void flushBuffer() throws IOException { 276 servletResponse.flushBuffer(); 277 } 278 279 @Override 280 public void resetBuffer() { 281 servletResponse.resetBuffer(); 282 } 283 284 @Override 285 public boolean isCommitted() { 286 return servletResponse.isCommitted(); 287 } 288 289 @Override 290 public void reset() { 291 servletResponse.reset(); 292 } 293 294 @Override 295 public void setLocale(Locale loc) { 296 servletResponse.setLocale(loc); 297 } 298 299 @Override 300 public Locale getLocale() { 301 return servletResponse.getLocale(); 302 } 303 }
StaticResourceProcessor:
1 package chapter2; 2 3 import java.io.IOException; 4 5 /** 6 * Created by kanyuxia on 2017/4/19. 7 * HttpServer静态资源处理类 8 */ 9 public class StaticResourceProcessor { 10 /** 11 * 静态资源处理方法 12 * @param request 请求对象 13 * @param response 响应对象 14 */ 15 public void process(Request request, Response response) { 16 try { 17 response.sendStaticResource(); 18 } catch (IOException e) { 19 e.printStackTrace(); 20 } 21 } 22 }
ServletProcessor:
1 package note1; 2 3 import javax.servlet.Servlet; 4 import javax.servlet.ServletException; 5 import java.io.IOException; 6 7 /** 8 * Created by kanyuxia on 2017/4/24. 9 * HttpServer Servelt请求处理类 10 */ 11 public class ServletProcessor { 12 /** 13 * 处理Servlet请求方法 14 * @param request 请求对象 15 * @param response 响应对象 16 */ 17 public void process(Request request, Response response) { 18 String url = request.getUrl(); 19 String servletName = url.substring(url.lastIndexOf("/") + 1); 20 // 从容器中拿到该Servlet 21 Servlet servlet = ServletContainer.container.get(servletName); 22 if (servlet != null) { 23 // 使用门面模式 24 RequestFacade requestFacade = new RequestFacade(request); 25 ResponseFacade responseFacade = new ResponseFacade(response); 26 try { 27 servlet.service(requestFacade, responseFacade); 28 } catch (ServletException e) { 29 e.printStackTrace(); 30 } catch (IOException e) { 31 e.printStackTrace(); 32 } 33 return; 34 } 35 // Servlet不存在 36 response.sendNotFound(); 37 } 38 }
PrimitiveServlet:
1 package note1; 2 3 import javax.servlet.*; 4 import java.io.IOException; 5 import java.io.PrintWriter; 6 7 8 /** 9 * Created by kanyuxia on 2017/4/19. 10 */ 11 public class PrimitiveServlet implements Servlet { 12 @Override 13 public void init(ServletConfig config) throws ServletException { 14 System.out.println("Primitive.init()"); 15 } 16 17 @Override 18 public ServletConfig getServletConfig() { 19 return null; 20 } 21 22 @Override 23 public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { 24 String header = "HTTP/1.1 200 OK\r\n" 25 + "Content-Type: text/html;charset=UTF-8\r\n" 26 + "\r\n"; 27 String content = "<html>\r\n" + 28 "<head>" + 29 "</head>" + 30 "<body>" + 31 "Primitive Servlet" + 32 "</body>" + 33 "</html>"; 34 PrintWriter writer = res.getWriter(); 35 writer.write(header); 36 writer.write(content); 37 writer.flush(); 38 writer.close(); 39 } 40 41 @Override 42 public String getServletInfo() { 43 return null; 44 } 45 46 @Override 47 public void destroy() { 48 System.out.println("Primitive.destory()"); 49 } 50 }
ServletContainer:
1 package note1; 2 3 import javax.servlet.Servlet; 4 import java.io.File; 5 import java.io.FileFilter; 6 import java.io.IOException; 7 import java.net.URL; 8 import java.net.URLClassLoader; 9 import java.net.URLStreamHandler; 10 import java.util.HashMap; 11 import java.util.Map; 12 13 /** 14 * Created by kanyuxia on 2017/4/24. 15 * Servlet容器:管理Servlet. 16 */ 17 public class ServletContainer { 18 /** 19 * 存放Servlet 20 */ 21 public static Map<String, Servlet> container = new HashMap<>(); 22 23 /** 24 * 初始化所有的Servlet 25 */ 26 @SuppressWarnings("unchecked") 27 public void init() { 28 // 创建URLClassLoader 29 URLClassLoader classLoader = null; 30 try { 31 // 创建URL 32 URL[] urls = new URL[1]; 33 File classPath = new File(HttpServer.SERVLET_ROOT); 34 String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString(); 35 URLStreamHandler streamHandler = null; 36 urls[0] = new URL(null, repository, streamHandler); 37 classLoader = new URLClassLoader(urls); 38 } catch (IOException e) { 39 System.out.println(); 40 } 41 // 获得指定目录下的所有.class文件 42 File path = new File(HttpServer.SERVLET_ROOT); 43 File[] files = path.listFiles(new FileFilter() { 44 @Override 45 public boolean accept(File pathname) { 46 return pathname.toString().endsWith(".class"); 47 } 48 }); 49 // 加载所有的.class文件 50 for (File file : files) { 51 String servletName = file.getName().substring(0, file.getName().indexOf(".")); 52 Class<Servlet> servletClass = null; 53 try { 54 servletClass = (Class<Servlet>) classLoader.loadClass(servletName); 55 } catch (ClassNotFoundException e) { 56 e.printStackTrace(); 57 } 58 Servlet servlet = null; 59 try { 60 servlet = servletClass.newInstance(); 61 } catch (InstantiationException e) { 62 e.printStackTrace(); 63 } catch (IllegalAccessException e) { 64 e.printStackTrace(); 65 } 66 ServletContainer.container.put(servletName, servlet); 67 } 68 } 69 }
Test:
1 package note1; 2 3 /** 4 * Created by kanyuxia on 2017/4/24. 5 */ 6 public class Test { 7 public static void main(String[] args) { 8 // 加载Servlet 9 ServletContainer servletContainer = new ServletContainer(); 10 servletContainer.init(); 11 // 启动HttpServer 12 HttpServer httpServer = new HttpServer(); 13 httpServer.start(); 14 } 15 }
《How Tomcat Works》读书笔记(二)