Servlet 源码分析

一、 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 不同类型的请求,再路由到不同的处理方法进行处理

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

plenilune-望月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值