《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

转载于:https://www.cnblogs.com/maying3010/p/6759597.html

《How Tomcat Works》读书笔记(二)相关推荐

  1. 深入理解JVM读书笔记二: 垃圾收集器与内存分配策略

    3.2对象已死吗? 3.2.1 引用计数法 给对象添加一个引用计数器,每当有一个地方引用它的地方,计数器值+1:当引用失效,计数器值就减1;任何时候计数器为0,对象就不可能再被引用了. 它很难解决对象 ...

  2. 《Docker 技术入门与实践》-读书笔记二

    <Docker 技术入门与实践>-读书笔记一 <Docker 技术入门与实践>-读书笔记二 一.数据管理 用户在使用 Docker 的过程中,往往需要能查看容器内应用产生的数据 ...

  3. 《Introduction To Modern Cryptography》读书笔记二

    <Introduction To Modern Cryptography>读书笔记二 本笔记纯粹个人读书习惯与相应见解,内容归纳完全出于个人需要与个人局限,如有修改意见(比如哪儿应该是值得 ...

  4. oracle直查和call哪个更快,让oracle跑的更快1读书笔记二

    当前位置:我的异常网» 数据库 » <>读书笔记二 <>读书笔记二 www.myexceptions.net  网友分享于:2013-08-23  浏览:9次 <> ...

  5. 3D游戏设计读书笔记二

    3D游戏设计读书笔记二 一.简答题 • 解释 游戏对象(GameObjects) 和 资源(Assets)的区别与联系.   GameObjects是一个具体的实例,Assets是包括诸多游戏素材的资 ...

  6. 《李元芳履职记》读书笔记二 IT技术管理的沟通与团队建设

    <李元芳履职记>读书笔记二 接一 https://blog.csdn.net/qq_45937199/article/details/103305223 IT技术人员从技术岗走向管理岗,所 ...

  7. python图像处理《数字图像处理与python实现》读书笔记二:空间滤波

    文章目录 重要! 第三章 空间滤波 概览 3.1 空间滤波基础 3.1.1 空间滤波的机理 3.1.2 空间滤波器模板 3.2 平滑处理 3.2.1 平滑线性空间滤波器 3.2.2 统计排序滤波器 3 ...

  8. 第一行代码 Android读书笔记(二)

    第一行代码 Android读书笔记 第三章 软件也要拼脸蛋-UI开发的点点滴滴 常用控件的使用方法 详解4种基本布局 自定义控件 最常用和最难用的控件-ListView 更加强大的滚动控件-Recyc ...

  9. 《淘宝技术这十年》读书笔记 (二).Java时代的脱胎换骨和坚若磐石

    马云说过"一个好的东西往往是是说不清楚的",姑且不论这句话的对与错.但我真的很佩服<淘宝技术这十年>这本书的作者子柳,能够通过淘宝的一些故事,按照时间顺序和IT发展的各 ...

最新文章

  1. 【linux】error: stdio.h: No such file or directory
  2. 再见,Python!!
  3. mysql 索引分析工具_Mysql:性能分析以及Explain工具的使用
  4. maven web项目保存log4j日志到WEB-INF
  5. 使用SparkJava和Graal的本机微服务
  6. javaScript学习笔记之类型转换
  7. 多线程调用同一个对象的方法_多线程之如何创建和使用线程
  8. Linux安装nextcloud教程,WSL下安装nextcloud
  9. 计算机自动生成凭证,哪些财务软件能自动生成记账凭证?
  10. 创建脚本的步骤整理(转发)
  11. elasticsearch 文档增删改
  12. C1认证之计算机通识知识及习题总结——我的学习笔记
  13. Gym 100015H Hidden Code
  14. LeetCode精选TOP面试题(中等篇)【出现率降序】
  15. [WDS] Disconnected解决方法
  16. oracle实例由,Oracle 数据库的实例由( )组成
  17. 算法 64式 7、搜索算法整理_第1部分_1到15题
  18. oracle两个压缩包怎么解压,AIX下如何解压缩zip文件
  19. 玩转curl指令—测试简单的HTTP接口
  20. 抽象函数的对称性验证

热门文章

  1. Android初步学习BroadCast与Service实现简单的音乐播放器
  2. 使用Python实现Hadoop MapReduce程序
  3. python numpy使用
  4. 利用Win32 Debug API打造自己的调试器Debugger
  5. 当前的三种构件标准规范
  6. Apache Spark学习:利用Eclipse构建Spark集成开发环境
  7. 大厂动态规划面试汇总,提升内功
  8. 腾讯面试:比特位计数
  9. 虚函数表 vtable
  10. 缓冲区溢出以及缓冲区溢出攻击