详解Servlet 笔记

    Servlet是Servlet+Applet缩写,表示服务器应用。Servlet就是一套规范,按照这套规范写的代码可以直接在Java的服务器上面运行。

   Servlet3.1中Servlet的结构

 

1. Servlet接口

    Servlet3.1的接口规范

public interface Servlet {
  	// init方法在容器启动时被容器调用(load-on-startup设置为负数或者不设置时会在Servlet第一次用到时才被调用),只会调用一次,容器传进入一个ServletConfig类型的参数(如配置文件等)
    void init(ServletConfig var1) throws ServletException;
    // 获取ServletConfig
  	ServletConfig getServletConfig();
    // 具体处理一个请求
    void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
  	// 获取Servlet相关的信息,自己实现,默认返回空字符串
    String getServletInfo();
    // Servlet销毁时释放资源,只会调用一次
    void destroy();
}


    Tomcat中Servlet的init方法在StandardWrapper的init方法中调用的,ServletConfig传入的事StandardWrapper(封装着Servlet)自身的门面类StandardWrapperFacade。Servlet是通过xml文件配置的,解析xml时把配置参数设置进入,StandardWrapper就包含配置项了。并不是StandardWrapper的所有内容都是Config相关的,所以用了门面Facede类。

public interface ServletConfig {    
  String getServletName();    
  ServletContext getServletContext();    
  String getInitParameter(String var1);    
  Enumeration<String> getInitParameterNames(); 
}

    getServletName获取 Servet的名字,就是web.xml定义的servlet-name;

    getInitParameter获取 init-param配置的参数

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

    getServletContext返回ServletContext代表这个应用本身,ServletContext就是Tomcat中Context的门面类 ApplicationContextFacade(参考StandardContext的getServletContext方法)。ServletContext代表应用本身,ServletContext设置的参数就可以被当前应用的所有Servlet共享了。项目中参数一般保存在session或者Application中,而ApplicationContext实现了ServletContext,很多时候就是保存在ServletContext中

    ServletConfig是Servlet级别的,而ServletContext是Context(Application)级别的。

    ServletContext接口中的getContext(String uripath)可以根据路径获取同个站点下别的应用的ServletContext。

    ServletConfig和ServletContext最常见使用是传递初始化参数。以Spring的contextConfigLocation参数为例

通过<context-param>配置的contextConfigLocation配置到ServletContext中,

<servlet>下的init-param配置的contextConfigLocation配置到了ServletConfig中

getServletConfig().getServletContext().getInitParameter("contextConfigLocation");
getServletConfig().getInitParameter("contextConfigLocation");

GenericServlet定义了getInitParameter方法,返回getServletConfig().getInitParameter()的返回值

ServletContext保存Applicaton级别的属性,可以使用setAttribute完成

getServletContext().setAttribute("contextConfigLocation","new path");

2 GenericServlet

GenericServlet 通用是Servlet的默认实现,主要做了三件事

   1. 实现了ServletConfig接口,可以直接调用ServletConfig里面的方法

   2. 提供无参的init方法

   3. 提供了log方法

  public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
       private transient ServletConfig config;
       public GenericServlet() {}
       public void destroy() {}
       public String getInitParameter(String name) {
           return this.getServletConfig().getInitParameter(name);
       }
       public ServletContext getServletContext() {
           return this.getServletConfig().getServletContext();
       }
       public void init(ServletConfig config) throws ServletException {
           this.config = config;
           this.init();
       }
       public void init() throws ServletException {}
       public void log(String msg) {
           this.getServletContext().log(this.getServletName() + ": " + msg);
       }
       public void log(String message, Throwable t) {
           this.getServletContext().log(this.getServletName() + ": " + message, t);
       }

GenericServlet实现了Servlet的init(ServletConfig config)方法,将config设置给内部变量config,然后调用无参init(),这个方法是个模版方法,在子类中可以覆盖它来完成自己的初始化工作

这种做法有三个作用:

   1. 将参数config设置给内部config,可以在ServletConfig的接口方法中直接调用config的相应方法来执行
   2. 我们在写Servlet时可以只处理自己的初始化逻辑,不需要管config
   3. 在重写init方法时不需要调用super.init(config)了。如果自己的Servlet中重写了带参数的init方法,一定要调用super.init(config),否则这里的config属性接收不到值,ServletConfig接口方法也不能执行了。

    GenericServlet提供了两个log方法,一个记录日志,一个记录异常。一般有自己的日志处理方式这个不常用。GenericServlet是与具体协议无关的。

3 HttpServlet

    HttpServlet用HTTP协议实现的Servlet的基类,写Servlet时继承它就可以。DispatcherServlet就是继承的HttpServlet。Http主要重写了service方法,将ServletRequest和ServletResponse转换为HttpServletRequest和HttpServletResponse,然后根据Http请求的类型将请求路由到不同的处理方法。

    具体处理方法是doXXX如doGet、doPost、doPut和doDelete方法都是模版方法,如果子类没有实现将抛出异常。

    doGet方法对是否过期做了检查,没有过期则直接返回304状态码使用缓存;doHead调用了doGet的请求,然后返回空body的Response;

    doOptions和doTrace正常不需要使用,主要用来做调试工作,doOptions返回所有支持的处理类型的集合,正常可以仅用,doTrace用来远程诊断服务器的,会将接受的header原封不动地返回,存在安全漏洞,最好禁用。HttpServlet为这两个方法做了默认实现。

public abstract class HttpServlet extends GenericServlet {
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        HttpServletRequest request;
        HttpServletResponse response;
        try {
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)res;
        } catch (ClassCastException var6) {
            throw new ServletException(lStrings.getString("http.non_http"));
        }

        this.service(request, response);
    }
     protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();
        long lastModified;
        if (method.equals("GET")) {
            lastModified = this.getLastModified(req);
            if (lastModified == -1L) {
                this.doGet(req, resp);
            } else {
                long ifModifiedSince;
                try {
                    ifModifiedSince = req.getDateHeader("If-Modified-Since");
                } catch (IllegalArgumentException var9) {
                    ifModifiedSince = -1L;
                }

                if (ifModifiedSince < lastModified / 1000L * 1000L) {
                    this.maybeSetLastModified(resp, lastModified);
                    this.doGet(req, resp);
                } else {
                    resp.setStatus(304);
                }
            }
        } else if (method.equals("HEAD")) {
            lastModified = this.getLastModified(req);
            this.maybeSetLastModified(resp, lastModified);
            this.doHead(req, resp);
        } else if (method.equals("POST")) {
            this.doPost(req, resp);
        } else if (method.equals("PUT")) {
            this.doPut(req, resp);
        } else if (method.equals("DELETE")) {
            this.doDelete(req, resp);
        } else if (method.equals("OPTIONS")) {
            this.doOptions(req, resp);
        } else if (method.equals("TRACE")) {
            this.doTrace(req, resp);
        } else {
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[]{method};
            errMsg = MessageFormat.format(errMsg, errArgs);
            resp.sendError(501, errMsg);
        }

    }
  }

    HttpServlet主要将不同的请求方式路由到不同的处理方法。

    SpringMVC中又将所有请求合并到了同一的一个方法进行处理。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值