一、 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 版权协议,转载请附上原文出处链接和本声明。