激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - 基于Java web服務器簡單實現一個Servlet容器

基于Java web服務器簡單實現一個Servlet容器

2020-05-19 10:40風一樣的碼農 JAVA教程

這篇文章主要為大家詳細介紹了基于Java web服務器簡單實現一個Servlet容器,感興趣的小伙伴們可以參考一下

上篇寫了一個簡單的Java web服務器實現,只能處理一些靜態資源的請求,本篇文章實現的Servlet容器基于前面的服務器做了個小改造,增加了Servlet請求的處理。

 程序執行步驟
 1.創建一個ServerSocket對象;
 2.調用ServerSocket對象的accept方法,等待連接,連接成功會返回一個Socket對象,否則一直阻塞等待;
 3.從Socket對象中獲取InputStream和OutputStream字節流,這兩個流分別對應request請求和response響應;
 4.處理請求:讀取InputStream字節流信息,轉成字符串形式,并解析,這里的解析比較簡單,僅僅獲取uri(統一資源標識符)信息;
 5.處理響應(分兩種類型,靜態資源請求響應或servlet請求響應):如果是靜態資源請求,則根據解析出來的uri信息,從WEB_ROOT目錄中尋找請求的資源資源文件, 讀取資源文件,并將其寫入到OutputStream字節流中;如果是Servlet請求,則首先生成一個URLClassLoader類加載器,加載請求的servlet類,創建servlet對象,執行service方法(往OutputStream寫入響應的數據);
 6.關閉Socket對象;
 7.轉到步驟2,繼續等待連接請求; 

代碼實現:
 添加依賴: 

?
1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/javax.servlet/servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.3</version>
</dependency>

服務器代碼: 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package ex02.pyrmont.first;
 
import java.net.Socket;
import java.net.ServerSocket;
import java.net.InetAddress;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
 
import ex02.pyrmont.Request;
import ex02.pyrmont.Response;
import ex02.pyrmont.StaticResourceProcessor;
 
public class HttpServer1 {
 
 // 關閉服務命令
 private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";
 
 public static void main(String[] args) {
 HttpServer1 server = new HttpServer1();
 //等待連接請求
 server.await();
 }
 
 public void await() {
 ServerSocket serverSocket = null;
 int port = 8080;
 try {
 //服務器套接字對象
 serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
 } catch (IOException e) {
 e.printStackTrace();
 System.exit(1);
 }
 
 // 循環等待請求
 while (true) {
 Socket socket = null;
 InputStream input = null;
 OutputStream output = null;
 try {
 //等待連接,連接成功后,返回一個Socket對象
 socket = serverSocket.accept();
 input = socket.getInputStream();
 output = socket.getOutputStream();
 
 // 創建Request對象并解析
 Request request = new Request(input);
 request.parse();
 // 檢查是否是關閉服務命令
 if (request.getUri().equals(SHUTDOWN_COMMAND)) {
  break;
 }
 
 // 創建 Response 對象
 Response response = new Response(output);
 response.setRequest(request);
 
 if (request.getUri().startsWith("/servlet/")) {
  //請求uri以/servlet/開頭,表示servlet請求
  ServletProcessor1 processor = new ServletProcessor1();
  processor.process(request, response);
 } else {
  //靜態資源請求
  StaticResourceProcessor processor = new StaticResourceProcessor();
  processor.process(request, response);
 }
 
 // 關閉 socket
 socket.close();
 
 } catch (Exception e) {
 e.printStackTrace();
 System.exit(1);
 }
 }
 }
}

常量類: 

?
1
2
3
4
5
6
7
8
9
10
11
package ex02.pyrmont;
 
import java.io.File;
 
public class Constants {
 public static final String WEB_ROOT = System.getProperty("user.dir")
 + File.separator + "webroot";
 public static final String WEB_SERVLET_ROOT = System.getProperty("user.dir")
 + File.separator + "target" + File.separator + "classes";
 
}

Request: 

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
package ex02.pyrmont;
 
import java.io.InputStream;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Map;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
 
public class Request implements ServletRequest {
 
 private InputStream input;
 private String uri;
 
 public Request(InputStream input) {
 this.input = input;
 }
 
 public String getUri() {
 return uri;
 }
 /**
 *
 * requestString形式如下:
 * GET /index.html HTTP/1.1
 * Host: localhost:8080
 * Connection: keep-alive
 * Cache-Control: max-age=0
 * ...
 * 該函數目的就是為了獲取/index.html字符串
 */
 private String parseUri(String requestString) {
 int index1, index2;
 index1 = requestString.indexOf(' ');
 if (index1 != -1) {
 index2 = requestString.indexOf(' ', index1 + 1);
 if (index2 > index1)
 return requestString.substring(index1 + 1, index2);
 }
 return null;
 }
 //從InputStream中讀取request信息,并從request中獲取uri值
 public void parse() {
 // Read a set of characters from the socket
 StringBuffer request = new StringBuffer(2048);
 int i;
 byte[] buffer = new byte[2048];
 try {
 i = input.read(buffer);
 } catch (IOException e) {
 e.printStackTrace();
 i = -1;
 }
 for (int j = 0; j < i; j++) {
 request.append((char) buffer[j]);
 }
 System.out.print(request.toString());
 uri = parseUri(request.toString());
 }
 
 /* implementation of the ServletRequest */
 public Object getAttribute(String attribute) {
 return null;
 }
 
 public Enumeration<?> getAttributeNames() {
 return null;
 }
 
 public String getRealPath(String path) {
 return null;
 }
 
 public RequestDispatcher getRequestDispatcher(String path) {
 return null;
 }
 
 public boolean isSecure() {
 return false;
 }
 
 public String getCharacterEncoding() {
 return null;
 }
 
 public int getContentLength() {
 return 0;
 }
 
 public String getContentType() {
 return null;
 }
 
 public ServletInputStream getInputStream() throws IOException {
 return null;
 }
 
 public Locale getLocale() {
 return null;
 }
 
 public Enumeration<?> getLocales() {
 return null;
 }
 
 public String getParameter(String name) {
 return null;
 }
 
 public Map<?, ?> getParameterMap() {
 return null;
 }
 
 public Enumeration<?> getParameterNames() {
 return null;
 }
 
 public String[] getParameterValues(String parameter) {
 return null;
 }
 
 public String getProtocol() {
 return null;
 }
 
 public BufferedReader getReader() throws IOException {
 return null;
 }
 
 public String getRemoteAddr() {
 return null;
 }
 
 public String getRemoteHost() {
 return null;
 }
 
 public String getScheme() {
 return null;
 }
 
 public String getServerName() {
 return null;
 }
 
 public int getServerPort() {
 return 0;
 }
 
 public void removeAttribute(String attribute) {
 }
 
 public void setAttribute(String key, Object value) {
 }
 
 public void setCharacterEncoding(String encoding)
 throws UnsupportedEncodingException {
 }
 
}

Response: 

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package ex02.pyrmont;
 
import java.io.OutputStream;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.File;
import java.io.PrintWriter;
import java.util.Locale;
import javax.servlet.ServletResponse;
import javax.servlet.ServletOutputStream;
 
public class Response implements ServletResponse {
 
 private static final int BUFFER_SIZE = 1024;
 Request request;
 OutputStream output;
 PrintWriter writer;
 
 public Response(OutputStream output) {
 this.output = output;
 }
 
 public void setRequest(Request request) {
 this.request = request;
 }
 
 //將web文件寫入到OutputStream字節流中
 public void sendStaticResource() throws IOException {
 byte[] bytes = new byte[BUFFER_SIZE];
 FileInputStream fis = null;
 try {
 /* request.getUri has been replaced by request.getRequestURI */
 File file = new File(Constants.WEB_ROOT, request.getUri());
 fis = new FileInputStream(file);
 /*
 * HTTP Response = Status-Line(( general-header | response-header |
 * entity-header ) CRLF) CRLF [ message-body ] Status-Line =
 * HTTP-Version SP Status-Code SP Reason-Phrase CRLF
 */
 int ch = fis.read(bytes, 0, BUFFER_SIZE);
 while (ch != -1) {
 output.write(bytes, 0, ch);
 ch = fis.read(bytes, 0, BUFFER_SIZE);
 }
 } catch (FileNotFoundException e) {
 String errorMessage = "HTTP/1.1 404 File Not Found\r\n"
  + "Content-Type: text/html\r\n" + "Content-Length: 23\r\n"
  + "\r\n" + "<h1>File Not Found</h1>";
 output.write(errorMessage.getBytes());
 } finally {
 if (fis != null)
 fis.close();
 }
 }
 
 /** implementation of ServletResponse */
 public void flushBuffer() throws IOException {
 }
 
 public int getBufferSize() {
 return 0;
 }
 
 public String getCharacterEncoding() {
 return null;
 }
 
 public Locale getLocale() {
 return null;
 }
 
 public ServletOutputStream getOutputStream() throws IOException {
 return null;
 }
 
 public PrintWriter getWriter() throws IOException {
 // autoflush is true, println() will flush,
 // but print() will not.
 writer = new PrintWriter(output, true);
 return writer;
 }
 
 public boolean isCommitted() {
 return false;
 }
 
 public void reset() {
 }
 
 public void resetBuffer() {
 }
 
 public void setBufferSize(int size) {
 }
 
 public void setContentLength(int length) {
 }
 
 public void setContentType(String type) {
 }
 
 public void setLocale(Locale locale) {
 }
}

靜態資源請求處理: 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package ex02.pyrmont;
 
import java.io.IOException;
 
public class StaticResourceProcessor {
 
 public void process(Request request, Response response) {
 try {
 response.sendStaticResource();
 } catch (IOException e) {
 e.printStackTrace();
 }
 }
}

Servlet請求處理: 

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package ex02.pyrmont.first;
 
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandler;
import java.io.IOException;
 
import javax.servlet.Servlet;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
 
import ex02.pyrmont.Constants;
import ex02.pyrmont.Request;
import ex02.pyrmont.Response;
 
public class ServletProcessor1 {
 
 public void process(Request request, Response response) {
 
 String uri = request.getUri();
 String servletName = uri.substring(uri.lastIndexOf("/") + 1);
 
 //類加載器,用于從指定JAR文件或目錄加載類
 URLClassLoader loader = null;
 try {
 URLStreamHandler streamHandler = null;
 //創建類加載器
 loader = new URLClassLoader(new URL[]{new URL(null, "file:" + Constants.WEB_SERVLET_ROOT, streamHandler)});
 } catch (IOException e) {
 System.out.println(e.toString());
 }
 
 Class<?> myClass = null;
 try {
 //加載對應的servlet類
 myClass = loader.loadClass(servletName);
 } catch (ClassNotFoundException e) {
 System.out.println(e.toString());
 }
 
 Servlet servlet = null;
 
 try {
 //生產servlet實例
 servlet = (Servlet) myClass.newInstance();
 //執行ervlet的service方法
 servlet.service((ServletRequest) request,(ServletResponse) response);
 } catch (Exception e) {
 System.out.println(e.toString());
 } catch (Throwable e) {
 System.out.println(e.toString());
 }
 
 }
}

Servlet類: 

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import javax.servlet.*;
import java.io.IOException;
import java.io.PrintWriter;
 
public class PrimitiveServlet implements Servlet {
 
 public void init(ServletConfig config) throws ServletException {
 System.out.println("init");
 }
 
 public void service(ServletRequest request, ServletResponse response)
 throws ServletException, IOException {
 System.out.println("from service");
 PrintWriter out = response.getWriter();
 out.println("Hello. Roses are red.");
 out.print("Violets are blue.");
 }
 
 public void destroy() {
 System.out.println("destroy");
 }
 
 public String getServletInfo() {
 return null;
 }
 
 public ServletConfig getServletConfig() {
 return null;
 }
 
}

結果測試:
 靜態資源請求:

基于Java web服務器簡單實現一個Servlet容器

servlet請求(因為只是第一個字符串被刷新到瀏覽器,所以你不能看到第二個字符串Violets are blue。我們將在后續完善該容器):

基于Java web服務器簡單實現一個Servlet容器

改進

前面實現的Servlet容器有一個嚴重的問題,用戶在servlet里可以直接將ServletRequest、ServletResponse向下轉 型為Request和Response類型,并直接調用其內部的public方法,這是一個不好的設計,改進方法是給Request、Response 增加外觀類,這樣,用戶只能訪問外觀類里定義的public方法。
 Request外觀類

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package ex02.pyrmont.second;
 
import java.io.IOException;
import java.io.BufferedReader;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Map;
 
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
 
import ex02.pyrmont.Request;
 
public class RequestFacade implements ServletRequest {
 
 private ServletRequest request = null;
 
 public RequestFacade(Request request) {
 this.request = request;
 }
 
 /* implementation of the ServletRequest */
 public Object getAttribute(String attribute) {
 return request.getAttribute(attribute);
 }
 
 public Enumeration<?> getAttributeNames() {
 return request.getAttributeNames();
 }
 
 @SuppressWarnings("deprecation")
 public String getRealPath(String path) {
 return request.getRealPath(path);
 }
 
 public RequestDispatcher getRequestDispatcher(String path) {
 return request.getRequestDispatcher(path);
 }
 
 public boolean isSecure() {
 return request.isSecure();
 }
 
 public String getCharacterEncoding() {
 return request.getCharacterEncoding();
 }
 
 public int getContentLength() {
 return request.getContentLength();
 }
 
 public String getContentType() {
 return request.getContentType();
 }
 
 public ServletInputStream getInputStream() throws IOException {
 return request.getInputStream();
 }
 
 public Locale getLocale() {
 return request.getLocale();
 }
 
 public Enumeration<?> getLocales() {
 return request.getLocales();
 }
 
 public String getParameter(String name) {
 return request.getParameter(name);
 }
 
 public Map<?, ?> getParameterMap() {
 return request.getParameterMap();
 }
 
 public Enumeration<?> getParameterNames() {
 return request.getParameterNames();
 }
 
 public String[] getParameterValues(String parameter) {
 return request.getParameterValues(parameter);
 }
 
 public String getProtocol() {
 return request.getProtocol();
 }
 
 public BufferedReader getReader() throws IOException {
 return request.getReader();
 }
 
 public String getRemoteAddr() {
 return request.getRemoteAddr();
 }
 
 public String getRemoteHost() {
 return request.getRemoteHost();
 }
 
 public String getScheme() {
 return request.getScheme();
 }
 
 public String getServerName() {
 return request.getServerName();
 }
 
 public int getServerPort() {
 return request.getServerPort();
 }
 
 public void removeAttribute(String attribute) {
 request.removeAttribute(attribute);
 }
 
 public void setAttribute(String key, Object value) {
 request.setAttribute(key, value);
 }
 
 public void setCharacterEncoding(String encoding)
  throws UnsupportedEncodingException {
 request.setCharacterEncoding(encoding);
 }
 
}

Response外觀類

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package ex02.pyrmont.second;
 
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Locale;
 
import javax.servlet.ServletResponse;
import javax.servlet.ServletOutputStream;
 
import ex02.pyrmont.Response;
 
public class ResponseFacade implements ServletResponse {
 
 private ServletResponse response;
 
 public ResponseFacade(Response response) {
 this.response = response;
 }
 
 public void flushBuffer() throws IOException {
 response.flushBuffer();
 }
 
 public int getBufferSize() {
 return response.getBufferSize();
 }
 
 public String getCharacterEncoding() {
 return response.getCharacterEncoding();
 }
 
 public Locale getLocale() {
 return response.getLocale();
 }
 
 public ServletOutputStream getOutputStream() throws IOException {
 return response.getOutputStream();
 }
 
 public PrintWriter getWriter() throws IOException {
 return response.getWriter();
 }
 
 public boolean isCommitted() {
 return response.isCommitted();
 }
 
 public void reset() {
 response.reset();
 }
 
 public void resetBuffer() {
 response.resetBuffer();
 }
 
 public void setBufferSize(int size) {
 response.setBufferSize(size);
 }
 
 public void setContentLength(int length) {
 response.setContentLength(length);
 }
 
 public void setContentType(String type) {
 response.setContentType(type);
 }
 
 public void setLocale(Locale locale) {
 response.setLocale(locale);
 }
 
}

處理Servlet請求類: 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package ex02.pyrmont.second;
 
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandler;
import java.io.IOException;
 
import javax.servlet.Servlet;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
 
import ex02.pyrmont.Constants;
import ex02.pyrmont.Request;
import ex02.pyrmont.Response;
 
public class ServletProcessor2 {
 
 public void process(Request request, Response response) {
 
 String uri = request.getUri();
 String servletName = uri.substring(uri.lastIndexOf("/") + 1);
 // 類加載器,用于從指定JAR文件或目錄加載類
 URLClassLoader loader = null;
 try {
  URLStreamHandler streamHandler = null;
  // 創建類加載器
  loader = new URLClassLoader(new URL[] { new URL(null, "file:"
   + Constants.WEB_SERVLET_ROOT, streamHandler) });
 } catch (IOException e) {
  System.out.println(e.toString());
 }
 
 Class<?> myClass = null;
 try {
  // 加載對應的servlet類
  myClass = loader.loadClass(servletName);
 } catch (ClassNotFoundException e) {
  System.out.println(e.toString());
 }
 
 Servlet servlet = null;
 //給request、response增加外觀類,安全性考慮,防止用戶在servlet里直接將ServletRequest、ServletResponse向下轉型為Request和Response類型,
 //并直接調用其內部的public方法,因為RequestFacade、ResponseFacade里不會有parse、sendStaticResource等方法;
 RequestFacade requestFacade = new RequestFacade(request);
 ResponseFacade responseFacade = new ResponseFacade(response);
 try {
  servlet = (Servlet) myClass.newInstance();
  servlet.service((ServletRequest) requestFacade, (ServletResponse) responseFacade);
 } catch (Exception e) {
  System.out.println(e.toString());
 } catch (Throwable e) {
  System.out.println(e.toString());
 }
 
 }
}

其它代碼與前面實現的Servlet容器基本一致。
 驗證程序,分別請求靜態資源和Servlet,發現結果與前面實現的容器一致;

 參考資料:《深入剖析Tomcat》

@author   風一樣的碼農

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:http://www.cnblogs.com/chenpi/archive/2016/06/21/5603072.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 免费在线一区二区 | 久久精品中文字幕一区二区 | 香蕉成人在线观看 | 一级黄色在线观看 | 久久综合艹 | 99久久九九爱看免费直播 | 在线播放免费播放av片 | 亚洲aⅴ免费在线观看 | 美女视频黄a视频免费全过程 | 国产另类一区 | 日韩欧美电影在线观看 | 国产一级毛片高清视频 | 国产精品免费久久久久 | 91一区二区三区久久久久国产乱 | 美女扒开腿让男生桶爽网站 | 视频在线中文字幕 | 免费h片| 综合日韩av | 91麻豆精品国产91久久久更新资源速度超快 | 护士hd欧美free性xxxx | 国产精品久久久久久久久久iiiii | 日韩精品一区不卡 | 法国极品成人h版 | 欧美大电影免费观看 | 国产精品久久久久久婷婷天堂 | 久久精品一区二区三区不卡牛牛 | 鸳鸯谱在线观看高清 | 暴力肉体进入hdxxxx0 | 久久国产精品91 | 欧美 日韩 亚洲 中文 | 国产二区三区四区 | 国产伊人色 | 91小视频在线观看免费版高清 | 羞羞网站在线观看入口免费 | 国产亚洲高清在线精品不卡 | 久久国产一二三 | 国产妇女乱码一区二区三区 | 香蕉视频99| a级高清免费毛片av在线 | 精品久久久久久久久久久久包黑料 | 日本精品免费观看 |