Servlet 源码分析

  • Post author:
  • Post category:其他


一、 Servlet  源码分析

1 Servlet  结构图

Servlet 和 ServletConfig 都是顶层接口,而 GenericServlet 实现了这两个顶层接口,然后HttpServlet 继承了 GenericServlet 类.所以要实现一个 Servlet 直接就可以继承 HttpServlet

2 Servlet  接口

public interface Servlet {


//负责初始化 Servlet 对象。容器一旦创建好 Servlet 对象后,就调用此方法来初始化Servlet 对象

public void

init

(ServletConfig config) throws ServletException;

//负责处理客户的请求并返回响应。当容器接收到客户端要求访问特定的 servlet 请求时,就会调用 Servlet 的 service 方法

public void

service

(ServletRequest req, ServletResponse res) throws ServletException,IOException;

//Destroy()方法负责释放 Servlet 对象占用的资源,当 servlet 对象结束生命周期时,servlet 容器调用此方法来销毁 servlet 对象.

public void

destroy

();

//说明:Init(),service(),destroy() 这三个方法是 Servlet 生命周期中的最重要的三个方法。

//返回一个字符串,在该字符串中包含 servlet 的创建者,版本和版权等信息

public String

getServletInfo

();

//GetServletConfig: 返回一个 ServletConfig 对象,该对象中包含了 Servlet 初始化参数信息

public ServletConfig

getServletConfig

();

}

init 方法接收一个 ServletConfig 参数,由容器传入.ServletConfig 就是 Servlet 的配置,在web.xml 中定义 Servlet 时通过 init-param 标签配置的参数由 ServletConfig 保存

3 ServletConfig  接口

public interface ServletConfig {


//用于获取 Servlet 名,web.xml 中定义的 servlet-name

String

getServletName

();

//获取 Servlet 上下文对象(非常重要)

ServletContext

getServletContext

();

//获取 init-param 中的配置参数

String

getInitParameter

(String var1);

//获取配置的所有 init-param 名字集合

Enumeration<String>

getInitParameterNames

();

}

ServletConfig 是 Servlet 级别,而 ServletContext 是全局的

4 GenericServlet  抽象类

GenericServlet 是 Servlet 的默认实现,是与具体协议无关的

//抽象类 GenericServlet 实现了 Servlet 接口的同时,也实现了 ServletConfig 接口和Serializable 这两个接口

public

abstract

class

GenericServlet

implements

Servlet, ServletConfig

, java.io.Serializable

{


//私有变量,保存 init()传入的 ServletConfig 对象的引用

private transient ServletConfig config;

//无参的构造方法

public GenericServlet() { }

————————————

以下方法实现了 servlet 接口中的 5 个方法

实现 Servlet 接口方法开始

————————————

/*

实 现 接 口 Servlet 中 的 带 参 数 的 init(ServletConfig Config) 方 法 , 将 传 递 的

ServletConfig 对象的引用保存到私有成员变量中,

使得 GenericServlet 对象和一个 ServletConfig 对象关联.

同时它也调用了自身的不带参数的 init()方法

**/

public void

init

(ServletConfig config) throws ServletException {


this.config = config;

this.init(); //调用了无参的 init()方法

}

//无参的

init

()方法

public void init() throws ServletException {


}

//空实现了 destroy 方法

public void

destroy

() { }

//实现了接口中的 getServletConfig 方法,返回 ServletConfig 对象

public ServletConfig

getServletConfig

()

{


return config;

}

//该方法实现接口<Servlet>中的 ServletInfo,默认返回空字符串

public String

getServletInfo

() {


return “”;

}

//唯一没有实现的抽象方法 service(),仅仅在此声明。交由子类去实现具体的应用

//在后来的 HttpServlet 抽象类中,针对当前基于 Http 协议的 Web 开发,HttpServlet抽象类具体实现了这个方法

//若有其他的协议,直接继承本类后实现相关协议即可,具有很强的扩展性

public abstract void

service

(ServletRequest req, ServletResponse res)

throws ServletException,

IOException;

————————————

实现 Servlet 接口方法结束

————————————

———————————————

以下四个方法实现了接口 ServletConfig 中的方法

实现 ServletConfig 接口开始

———————————————

// 该 方 法 实 现 了 接 口 <ServletConfig> 中 的 getServletContext方法 用于返回servleConfig 对象中所包含的 servletContext 方法

public ServletContext

getServletContext

() {


return getServletConfig().getServletContext();

}

//获取初始化参数

public String

getInitParameter

(String name) {


return getServletConfig().getInitParameter(name);

}

//实现了接口<ServletConfig>中的方法,用于返回在 web.xml 文件中为 servlet 所配置的全部的初始化参数的值

public Enumeration getInitParameterNames() {


return getServletConfig().getInitParameterNames();

//获取在 web.xml 文件中注册的当前的这个 servlet 名称。没有在 web.xml 中注册的servlet,该方法直接放回该 servlet 的类名。

//法实现了接口<ServleConfig>中的 getServletName 方法

public String

getServletName

() {


return config.getServletName();

}

———————————————

实现 ServletConfig 接口结束

———————————————

public void

log

(String msg) {


getServletContext().log(getServletName() + “: “+ msg);

}

public void

log

(String message, Throwable t) {


getServletContext().log(getServletName() + “: ” + message, t);

}

}

5 基于协议的 HttpServlet

public

abstract

class

HttpServlet

extends

GenericServlet

implements java.io.Serializable

{


private static final String METHOD_GET = “GET”;

private static final String METHOD_POST = “POST”;

……

/**

* Does nothing, because this is an abstract class.

* 抽象类 HttpServlet 有一个构造函数,但是空的,什么都没有

*/

public HttpServlet() { }

/*分别执行 doGet,doPost,doOpitions,doHead,doPut,doTrace 方法

在请求响应服务方法 service()中,根据请求类型,分贝调用这些 doXXXX 方法

所以自己写的 Servlet 只需要根据请求类型覆盖响应的 doXXX 方法即可。

*/

//doXXXX 方法开始

protected void

doGet

(HttpServletRequest req, HttpServletResponse resp)

throws ServletException, IOException

{


String protocol = req.getProtocol();

String msg = lStrings.getString(“http.method_get_not_supported”);

if (protocol.endsWith(“1.1”)) {


resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED,msg);

} else {


resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);

}

}

protected void

doHead

(HttpServletRequest req, HttpServletResponse resp)

throws ServletException, IOException

{


…….

}

protected void

doPost

(HttpServletRequest req, HttpServletResponse resp)

throws ServletException, IOException

{


String protocol = req.getProtocol();

String msg = lStrings.getString(“http.method_post_not_supported”);

if (protocol.endsWith(“1.1”)) {


resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED,msg);

} else {


resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);

}

}

protected void

doPut

(HttpServletRequest req, HttpServletResponse resp)

throws ServletException, IOException {


//todo

}

protected void

doOptions

(HttpServletRequest req, HttpServletResponse resp)

throws ServletException, IOException {


//todo

}

protected void

doTrace

(HttpServletRequest req, HttpServletResponse resp)

throws ServletException, IOException {


//todo

}

protected void

doDelete

(HttpServletRequest req,HttpServletResponse resp)

throws ServletException, IOException {


//todo

}

//doXXXX 方法结束

//重载的 service(args0,args1)方法

protected void

service

(HttpServletRequest req, HttpServletResponse resp)

throws ServletException, IOException

{


String method = req.getMethod();

if (method.equals(METHOD_GET)) {


long lastModified = getLastModified(req);

if (lastModified == -1) {


// servlet doesn’t support if-modified-since, no reason

// to go through further expensive logic

doGet(req, resp);

} else {


long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);

if (ifModifiedSince < (lastModified / 1000 * 1000)) {


// If the servlet mod time is later, call doGet()

// Round down to the nearest second for a proper compare

//A ifModifiedSince of -1 will always be less

maybeSetLastModified(resp, lastModified);

doGet(req, resp);

} else {


resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);

}

}

} else if (method.equals(METHOD_HEAD)) {


long lastModified = getLastModified(req);

maybeSetLastModified(resp, lastModified);

doHead(req, resp);

} else if (method.equals(METHOD_POST)) {


doPost(req, resp);

} else if (method.equals(METHOD_PUT)) {


doPut(req, resp);

} else if (method.equals(METHOD_DELETE)) {


doDelete(req, resp);

} else if (method.equals(METHOD_OPTIONS)) {


doOptions(req,resp);

} else if (method.equals(METHOD_TRACE)) {


doTrace(req,resp);

} else {


//

// Note that this means NO servlet supports whatever

// method was requested, anywhere on this server.

//

String errMsg = lStrings.getString(“http.method_not_implemented”);

Object[] errArgs = new Object[1];

errArgs[0] = method;

errMsg = MessageFormat.format(errMsg, errArgs);

resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);

}

}

//实现父类的 service(ServletRequest req,ServletResponse res)方法

// 通 过 参 数 的 向 下 转 型 , 然 后 调 用 重 载 的service(HttpservletRequest,HttpServletResponse)方法

public void

service

(ServletRequest req, ServletResponse res)

throws ServletException, IOException

{


HttpServletRequest request;

HttpServletResponse response;

try {


request = (HttpServletRequest) req; //向下转型

response = (HttpServletResponse) res; //参数向下转型

} catch (ClassCastException e) {


throw new ServletException(“non-HTTP request or response”);

}

service(request, response); //调用重载的 service()方法

}

……//其他方法

}

HttpServlet是基于Http协议实现的Servlet基类,我们在写Servlet的时候直接继承它就行了.SpringMVC 中的 DispatchServlet 就是继承了 HttpServlet.HttpServlet 重新了 service 方法,而 service 方 法 首 先 将 ServletRequest 和 ServletResponse 转 成 HttpServletRequest 和HttpServletResponse,然后根据 Http 不同类型的请求,再路由到不同的处理方法进行处理



版权声明:本文为donglinjob原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。