首页 > 代码库 > 《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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

 

《How Tomcat Works》读书笔记(二)