一个简单的servlet容器
【0】README
0.1)本文部分文字转自 “深入剖析Tomcat”,旨在学习 一个简单的servlet容器 的基础知识;
0.2)for complete source code, please visit https://github.com/pacosonTang/HowTomcatWorks/tree/master/chapter2
0.3)文件目录如下:
【1】javax.servlet.Servlet接口
2.0)init, service, destroy方法是与 servlet的生命周期相关的方法;2.1)init方法:当实例化某个servlet类后;servlet容器会调用其 init() 方法进行初始化,servlet只调用该方法一次;且servlet 程序员可以覆盖此方法,在其中编写仅需要执行一次的初始化代码;2.2)service方法:当一个servlet客户端请求到达后,servlet容器就调用相应的servlet的service方法,并将 servletRequest 和 servletResponse 对象作为参数传入;2.3)destroy方法:当servlet容器关闭或servlet容器要释放内存时,才会将 servlet实例移除,而且只有当servlet实例的service方法中的所有线程都退出或执行超时后,才会调用 destroy方法;
t1)当第一次调用某个 servlet 时,要载入该 servlet类,并调用其 init() 方法;(仅此一次)t2)针对每个request请求, 创建一个 javax.servlet.ServletRequest 实例 和 一个 javax.servlet.ServletResponse 实例;t3)调用该 servlet 的 service() 方法,将 servletRequest对象和 servletResponse对象作为参数传入;t4)当关闭该servlet类时,调用其 destroy() 方法,并卸载该servlet类;
package com.tomcat.chapter2; import java.net.Socket;
import java.net.ServerSocket;
import java.net.InetAddress;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException; // HttpServer1 类 既可以对静态资源请求,也可以对servlet资源请求
public class HttpServer1 { /** WEB_ROOT is the directory where our HTML and other files reside.
* For this package, WEB_ROOT is the "webroot" directory under the working directory.
* The working directory is the location in the file system
* from where the java command was invoked.
*/
// shutdown command
private static final String SHUTDOWN_COMMAND = "/SHUTDOWN"; // the shutdown command received
private boolean shutdown = false; 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);
} // Loop waiting for a request
while (!shutdown) {
Socket socket = null;
InputStream input = null;
OutputStream output = null;
try {
socket = serverSocket.accept();
input = socket.getInputStream();
output = socket.getOutputStream(); // create Request object and parse
Request request = new Request(input);
request.parse(); // create Response object
Response response = new Response(output);
response.setRequest(request); // check if this is a request for a servlet or a static resource
// a request for a servlet begins with "/servlet/"
if (request.getUri().startsWith("/servlet/")) { // 若HTTP请求的是servlet(以servlet打头)
ServletProcessor1 processor = new ServletProcessor1();
processor.process(request, response);
} // 若http请求的是静态资源
else {
StaticResourceProcessor processor = new StaticResourceProcessor();
processor.process(request, response);
} // Close the socket
socket.close();
//check if the previous URI is a shutdown command
shutdown = request.getUri().equals(SHUTDOWN_COMMAND);
}
catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}
}
package com.tomcat.chapter2; import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandler;
import java.io.File;
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; // 用于处理对servlet 资源的HTTP 请求
public class ServletProcessor1 { public void process(Request request, Response response) { String uri = request.getUri();
String servletName = uri.substring(uri.lastIndexOf("/") + 1);
URLClassLoader loader = null; // 类载入器 try {
// create a URLClassLoader, 创建类载入器(类加载器是干货代码 )
URL[] urls = new URL[1];
URLStreamHandler streamHandler = null;
File classPath = new File(Constants.WEB_ROOT);
// the forming of repository is taken from the createClassLoader method in
// org.apache.catalina.startup.ClassLoaderFactory
String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString() ;
// file:E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\webroot\
// the code for forming the URL is taken from the addRepository method in
// org.apache.catalina.loader.StandardClassLoader class.
urls[0] = new URL(null, repository, streamHandler);
// urls[0] = file:E:/bench-cluster/cloud-data-preprocess/HowTomcatWorks/webroot/
loader = new URLClassLoader(urls);
}
catch (IOException e) {
System.out.println(e.toString() );
}
Class myClass = null;
try {
myClass = loader.loadClass("servlet."+servletName); // 载入 servlet类
}
catch (ClassNotFoundException e) {
System.out.println(e.toString());
} Servlet servlet = null; try {
servlet = (Servlet) myClass.newInstance(); // 会创建已载入的servlet类的一个实例
servlet.service((ServletRequest) request, (ServletResponse) response);
}
catch (Exception e) {
System.out.println(e.toString());
}
catch (Throwable e) {
System.out.println(e.toString());
} }
}
package com.tomcat.chapter2; 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;
} 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;
} 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 {
} }
package com.tomcat.chapter2; 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;
} /* This method is used to serve a static page */
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) {
}
}
package com.tomcat.chapter2;
import java.io.IOException;
public class StaticResourceProcessor {
public void process(Request request, Response response) {
try {
response.sendStaticResource();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
package com.tomcat.chapter2;
import java.io.File;
public class Constants {
public static final String WEB_ROOT =
System.getProperty("user.dir") + File.separator + "webroot";
}
1.1)这是不安全的做法: 一旦我们有了Request 实例后,我们就可以调用其parse方法,而有了Response实例后,我们就可以调用其 sendStaticResource方法。不能将parse() 和 sendStaticResource() 设置为私有方法,因为它们会被其他类调用,但这两个方法在servlet中不应该是可用的;
2.1)构建外观类 RequestFacade 和 ResponseFacade:分别实现 ServletRequest 和 ServletResponse ,然后在其构造函数中指定Request 和 Response对象(private私有访问权限) ,外观类中的实现方法均调用 Request 或 Response对象的相应方法;
4.1)打印结果同 HttpServer1,故 omit it;4.2)源代码实现(我这里给给出外观类代码,其他和HttpServer1 中的类似)
package com.tomcat.chapter2; import java.net.Socket;
import java.net.ServerSocket;
import java.net.InetAddress;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException; public class HttpServer2 { // shutdown command
private static final String SHUTDOWN_COMMAND = "/SHUTDOWN"; // the shutdown command received
private boolean shutdown = false; public static void main(String[] args) {
HttpServer2 server = new HttpServer2();
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);
} // Loop waiting for a request
while (!shutdown) {
Socket socket = null;
InputStream input = null;
OutputStream output = null;
try {
socket = serverSocket.accept();
input = socket.getInputStream();
output = socket.getOutputStream(); // create Request object and parse
Request request = new Request(input);
request.parse(); // create Response object
Response response = new Response(output);
response.setRequest(request); //check if this is a request for a servlet or a static resource
//a request for a servlet begins with "/servlet/"
if (request.getUri().startsWith("/servlet/")) {
ServletProcessor2 processor = new ServletProcessor2();
processor.process(request, response);
}
else {
StaticResourceProcessor processor = new StaticResourceProcessor();
processor.process(request, response);
} // Close the socket
socket.close();
//check if the previous URI is a shutdown command
shutdown = request.getUri().equals(SHUTDOWN_COMMAND);
}
catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}
}
package com.tomcat.chapter2; 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 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();
} 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);
} }
package com.tomcat.chapter2; import java.io.IOException;
import java.io.PrintWriter;
import java.util.Locale;
import javax.servlet.ServletResponse;
import javax.servlet.ServletOutputStream; 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);
} }
package com.tomcat.chapter2; import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandler;
import java.io.File;
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; public class ServletProcessor2 { public void process(Request request, Response response) { String uri = request.getUri();
String servletName = uri.substring(uri.lastIndexOf("/") + 1);
URLClassLoader loader = null; try {
// create a URLClassLoader
URL[] urls = new URL[1];
URLStreamHandler streamHandler = null;
File classPath = new File(Constants.WEB_ROOT);
// the forming of repository is taken from the createClassLoader method in
// org.apache.catalina.startup.ClassLoaderFactory
String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString() ;
// the code for forming the URL is taken from the addRepository method in
// org.apache.catalina.loader.StandardClassLoader class.
urls[0] = new URL(null, repository, streamHandler);
loader = new URLClassLoader(urls);
}
catch (IOException e) {
System.out.println(e.toString() );
}
Class myClass = null;
try {
myClass = loader.loadClass("servlet." + servletName);
}
catch (ClassNotFoundException e) {
System.out.println(e.toString());
} Servlet servlet = null;
RequestFacade requestFacade = new RequestFacade(request); // attend this line
ResponseFacade responseFacade = new ResponseFacade(response); // attend this line
try {
servlet = (Servlet) myClass.newInstance();
servlet.service((ServletRequest) requestFacade, (ServletResponse) responseFacade); // attend this line
}
catch (Exception e) {
System.out.println(e.toString());
}
catch (Throwable e) {
System.out.println(e.toString());
} }
}
一个简单的servlet容器的更多相关文章
- 一个简单的Servlet容器实现
上篇写了一个简单的Java web服务器实现,只能处理一些静态资源的请求,本篇文章实现的Servlet容器基于前面的服务器做了个小改造,增加了Servlet请求的处理. 程序执行步骤 创建一个Serv ...
- how tomcat works 读书笔记(二)----------一个简单的servlet容器
app1 (建议读者在看本章之前,先看how tomcat works 读书笔记(一)----------一个简单的web服务器 http://blog.csdn.net/dlf123321/arti ...
- Tomcat学习笔记(二)—— 一个简单的Servlet容器
1.简介:Servlet编程是通过javax.Servlet和javax.servlet.http这两个包的类和接口实现的,其中javax.servlet.Servlet接口至关重要,所有的Servl ...
- 攻城狮在路上(肆)How tomcat works(二) 一个简单的servlet容器
该节在上一节的基础上增加了所谓对静态资源和动态资源访问的不同控制流程.示例里面采用的是对路径“/servlet/”进行了特殊处理. 一. 主要还是从HttpServer1中的main方法开始,先解析出 ...
- (2)自己写一个简单的servle容器
自己写一个简单的servlet,能够跑一个简单的servlet,说明一下逻辑. 首先是写一个简单的servlet,这就关联到javax.servlet和javax.servlet.http这两个包的类 ...
- Tomcat剖析(二):一个简单的Servlet服务器
Tomcat剖析(二):一个简单的Servlet服务器 1. Tomcat剖析(一):一个简单的Web服务器 2. Tomcat剖析(二):一个简单的Servlet服务器 3. Tomcat剖析(三) ...
- 探秘Tomcat——一个简易的Servlet容器
即便再简陋的服务器也是服务器,今天就来循着书本的第二章来看看如何实现一个servlet容器. 背景知识 既然说到servlet容器这个名词,我们首先要了解它到底是什么. servlet 相比你或多或少 ...
- 深入剖析tomcat之一个简单的servlet容器
上一篇,我们讲解了如果开发一个简单的Http服务器,这一篇,我们扩展一下,让我们的服务器具备servlet的解析功能. 简单介绍下Servlet接口 如果我们想要自定义一个Servlet,那么我们必须 ...
- Servlet复习1: 一个简单的Servlet的使用
Servlet学习 1. Servlet与JSP的关系 2. Servlet的声明周期 3. 一个简单的Servlet的使用方法 什么是Servlet? 什么又是JSP? 继承了javax.servl ...
随机推荐
- Linq中比较日期大小(部分比较)
问题:Linq中比较两个时间的年月日部分 表中某个字段的时间和系统时间比较大小(只比较年月日) 思路一:转换成字符串比较 var queryable = dbContext.Table .Where( ...
- JET 调用后端Rest Service
调用Rest Service可以基于两种方式: 一种是oj.Collection.extend 一种是$.ajax CORS问题 但在调用之前,首先需要解决rest service的CORS问题.(跨 ...
- iOS:App上架流程和支付宝支付流程
App上架大致流程: 1.花99美元在苹果开发中心注册一个开发者账号: 2.登陆开发者账号,进入member Center,即开发者成员中心: 3.选取证书标示符(certificates Ident ...
- artDialog弹出框使用
配置参数 名称 类型 默认值 描述 内容 title String '消息' 标题内容 content String 'loading..' 消息内容.1.如果传入的是HTMLElement类型,如果 ...
- 2017.11.15 hashmap的工作原理
参考来自:http://blog.csdn.net/jeffleo/article/details/54946424 一 hashMap的基本概念 1.HashMap的定义 public class ...
- ajax 底层源码解析
对象: XMLHttpRequest 属性:readyState请求状态,开始请求时值为0直到请求完成这个值增长到4 responseText目前为止接收到的响应体,readyState<3此属 ...
- C++五种迭代器之间的关系
迭代器操作 说明(1)所有迭代器p++ 后置自增迭代器++p ...
- jQuery OCUpload ——> 一键上传插件
OCUpload为jQuery的插件(One Click Upload),意思为一键上传,封装了对于文件上传的一些方法,只需几行代码,文件上传优雅而简洁. 对于传统的文件上传,只是通过inp ...
- Caused by: org.hibernate.boot.registry.selector.spi.StrategySelectionException: Unable to resolve name [org.hibernate.cache.ehcache.EhCacheRegionFactory] as strategy [org.hibernate.cache.spi.RegionFac
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springfram ...
- Redis之ziplist数据结构
0.前言 redis初始创建hash表,有序集合,链表时, 存储结构采用一种ziplist的存储结构, 这种结构内存排列更紧密, 能提高访存性能. 本文介绍ziplist数据结构 1.ziplist存 ...