Servlet源码解析

Servlet是JavaWeb应用中的最核心组件.而Servlet的生命周期又是通过Tomcat的Servlet容器调用的.首先看下JavaWeb的生命周期.

1.JavaWeb生命周期

  • 启动阶段:加载Web应用的有关数据,创建全局的ServletContext对象,对Filter和一些Servlet进行初始化.
  • 运行时阶段:为客户端提供服务.
  • 终止阶段:释放Web应用所占用的各种资源.

1.1 启动阶段:

一,把web.xml文件中的数据加载到内存中.
二,为JavaWeb应用创建一个ServletContext对象.
三,对所有Filter进行初始化.
四,对那些需要在启动阶段就初始化的Servlet类进行初始化(在配置文件中有< load-on-startup>标签的)

1.2 运行时阶段

该阶段中,所有的Servlet都处于待命状态,随时可以响应客户端的特定请求,提供响应的服务.

1.3 终止阶段

销毁处于运行的Servlet,Filter,销毁所有和JavaWeb应用相关对象,如ServletContext对象,并且释放Web应用所占用的相关资源.

2.Servlet API

首先看下servlet结构图:
这里写图片描述

2.1 Servlet

这里写图片描述
其中的3个方法由Servlet容器调用,关于Servlet容器具体怎么调用这些方法,需要研究Tomcat的原理,这里本人也不是很清楚:(

init(ServletConfig config) 方法:容器在创建好Servlet对象后,就会调用该方法。

service(ServletRequest req,ServletResponse res) 方法:当容器接收到客户端访问特定的Servlet对象时,调用该Servlet的service方法.

destory() 方法:当Servlet对象结束生命周期时,容器会调用这个方法.

2.2 ServletConfig

这里写图片描述

getServletContext():该方法会返回一个ServletContext,该对象是Servlet容器加入的,由于是父接口,故在其下面的子类都可以通过这个方法得到全局的ServletContext.

其他方法都是获取web.xml中设置的值,如给一个Servlet添加初始化的值,需要在定义servlet节点下加入< init-param>标签.

2.3 GenericServlet

public abstract class GenericServlet implements Servlet, ServletConfig,
        java.io.Serializable {

    private static final long serialVersionUID = 1L;

    private transient ServletConfig config;

    public GenericServlet() {
        // NOOP
    }

@Override
    public void destroy() {
        // NOOP by default
    }

 @Override
    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }

    public void init() throws ServletException {
        // NOOP by default
    }

@Override
    public ServletConfig getServletConfig() {
        return config;
    }

@Override
    public String getInitParameter(String name) {
        return getServletConfig().getInitParameter(name);
    }

@Override
    public abstract void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException;
...
...
...

很明显,该类是装饰类,其中有一个瞬时的ServletConfig对象,说明config对象在序列化时不会被保存到文件.

对于GenericServlet的子类,有两种初始化的方法,init()方法,如果想要与ServletConfig对象关联,在init()中加入super.init(config)就行了.

其中唯一的抽象方法是service(),指定子类为特定的客户实现的具体服务.

2.4 HttpServlet

这里写图片描述
其中定义了一些常量,如get方法,post方法,delete方法等.

2.4.1 doGet()

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);
        }
    }

如果子类中没有重写doGet方法的话,会返回一个错误码和错误信息,其中的判断语句判断的是客户与服务器之间是否采用HTTP1.1协议通信.

2.4.2 service(ServletRequest req, ServletResponse res)

@Override
    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(HttpServletRequest req, HttpServletResponse resp)方法上.

2.4.3 service(HttpServletRequest req, HttpServletResponse resp)

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;
                try {
                    ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                } catch (IllegalArgumentException iae) {
                    // Invalid date header - proceed as if none was set
                    ifModifiedSince = -1;
                }
                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);
        }
    }

该方法获取客户端的请求方式,然后根据请求方式来调用匹配的服务方法.如果为GET方式,就调用doGet()方法,以此类推.

3.ServletRequest ServletResponse

ServletRequest:
当Servlet容器接收到客户端要求访问特定Servlet的请求时,容器先解析客户端的原始请求数据,把它包装成一个ServletRequest对象,当容器调用Servlet对象的service()方法是,就可以把ServletRequest对象作为参数传给service()方法.

ServletResponse需要注意是:ServletResponse默认的正文MIME类型为text/plain,而HttpServletResponse的默认类型为text/html,即HTML文档类型.

4.ServletContext

这里写图片描述

4.1生命周期

当Servlet容器启动一个Web应用时,就会创建一个唯一的ServletContext对象,当Servlet容器终止一个Web应用时,就会销毁它的ServletContext对象,说明ServletContext生命周期和Web应用相同.

4.2 ServletContextListener

该监听器能监听ServletContext的生命周期,故可以使用它做一个网页被访问的次数.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值