1.详解Servlet

前言

       Servlet就是Server+Applet的缩写,表示一个服务器应用;

       Servlet其实就是一套规范,我们按照这个规范写的程序就可以直接在Java服务器上运行;


Servlet接口

public interface Servlet {
    
    //在容器启动的时候被调用,仅调用一次
    //当load-on-startup设置为负数或不设置的时候,会在Servlet第一次调用时才会被调用,仅调用一次
    void init(ServletConfig var1) throws ServletException;
    
    //获取Servlet的配置(ServletConfig)
    ServletConfig getServletConfig();
    
    //具体处理一个请求
    void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
    
    //获取与本Servlet相关的信息,如作者,版权等,这个方法需要自己实现,默认返回空字符串
    String getServletInfo();
    
    //用于在Servlet销毁(一般指关闭服务器)时释放资源,仅调用一次
    void destroy();
}

        Init方法在被调用时,会接收到一个ServletConfig类型的参数,它是容器传进去的;

     ServletConfig就是Servlet的配置;我们在web.xml中定义Servlet时,通过init-param标签配置的参数就是通过ServletConfig保存的;


        Tomcat在org.apache.catalina.core.StandardWrapper的initServlet方法中,调用Servlet的init方法;
        作为ServletConfig,传入的参数是StandardWrapper的门面类StandardWrapperFacade;
       这样的做法是很容易理解的,因为Servlet是通过xml配置的,解析xml的时候自然会把配置信息放到StandardWrapper中去,当然StandardWrapper包含的不仅仅是配置信息,所以就用了门面类;

ServletConfig接口

public interface ServletConfig {
    //用于获取Servlet名,web.xml中定义的servlet-name
    String getServletName();

    //非常重要:返回值ServletContext代表着这个应用本身
    ServletContext getServletContext();

    //获取init-param中的配置参数
    String getInitParameter(String var1);

    //获取配置的所有init-param名字集合
    Enumeration<String> getInitParameterNames();
}

     ServletContext就是Tomcat中Context的门面类ApplicationContextFacade,具体代码可以参考StandardContext的getServletContext;

      既然ServletContext代表着应用本身,所以ServletContext里设置的参数就可以被当前应用的所有Servlet共享。在项目当中,我们知道参数可以保存在Session和Application中,而后者很多时候就是保存在ServletContext中的。

     我们可以这么理解,ServletConfig是Servlet级别的,而ServletContext是Context(也就是Application)级别的。当然,ServletContext的功能非常强大,不是仅仅是保存参数;

      说到这,那有没有比ServletContext级别更高的呢?也就是Tomcat中Host级别的,还是有的。ServletContext中有个public ServletContext  getContext(String uirPath),它可以根据路径获取到同一站点下的别的应用的ServletContext。当然,为了安全,这个函数的返回值为null,可以手动更改。

      ServletConfig和ServletContext最常见的用途是,传递初始化参数。

    所以,为了方便,Servlet的第一个实现类GenericServlet定义了getInitParameter方法,内部返回getServletConfig.getInitParameter的返回值;
         另外,还需要说明的是,ServletContext通常保存的是Application级别的参数,这可以用setAttribute来完成;                         ServletContext和ServletConfig是保存的是两套独立的数据,互不影响;

GenericServlet实现类

        GenericServlet是Servlet的默认实现类,是与协议无关的;

        主要实现有三:

        1.实现了ServletConfig接口,可以直接调用它的方法,而不再需要事先获得ServletConfig对象;

         比如,获取ServletContext的时候,不再需要getServletConfig().getServletContxt(),直接调用getServletContxt()即可;


        2.提供了无参的init方法;

        3.提供了log方法:GenericServlet提供了2个log方法,一个记录日志,一个记录异常;具体实现是通过传给Servletontext的日志实现的;一般我们用自己的日志处理方式,所以这个用的不是很多;


HttpServlet实现类

        HttpServlet是用HTTP协议实现的Servlet的基类,DispatcherServlet就是继承自HttpServlet;如果要自定义Servlet,直接继承HttpServlet即可;

        HttpServlet是与协议相关的,所以更关心如何处理请求,即HttpServlet主要重写了service方法。在service方法中,首先将ServletRequest和ServletResponse转化为HttpServletRequest和HttpServletResponse,然后,根据Http请求类型的不同将请求路由到了不同的处理方法;

public void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException {

        HttpServletRequest  request;
        HttpServletResponse response;
       
        try {
            // 转换request和response的类型
            request = (HttpServletRequest) req;
            response = (HttpServletResponse) res;
        } catch (ClassCastException e) {
            throw new ServletException("non-HTTP request or response");
        }
        // 调用http的处理方式
        service(request, response);
}
 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 {         
            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);
        }
    }

       HttpServlet根据请求类型的不同将请求路由到不同的方法(doXXX,如doGet);子类需要对doXXX进行具体的实现,否则将抛出异常;

       HttpServlet主要将不同的请求方式路由到了不同的处理方法;不过Spring MVC又将所有的请求合并到了统一的一个方法进行处理;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值