servlet-servlet的简单认识

Posted whx20100101

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了servlet-servlet的简单认识相关的知识,希望对你有一定的参考价值。

 

Servlet的基本认识

本内容主要来源于《看透Spring MVC源码分析与实践——韩路彪》一书

Servlet是server+Applet的缩写,表示一个服务器的应用。Servlet其实就是一套规范。

一、servlet接口

  Servlet3.1中servlet接口定义如下:

public interface Servlet {

   //init方法在容器启动时被容器调用(当load-on-startup设置为负数或者不设置时会在Servlet第一次用到时才被调用),只会调用一次。
   public void init(ServletConfig config) throws ServletException;

   //getServletConfig方法用于获取ServletConfig。
   public ServletConfig geServletConfig();

    //service方法用于处理一个请求。
   public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;

   //getServletInfo方法可以获取一些Servlet相关的信息,这个方法需要自己去实现,默认返回空字符串。
   public String getServletInfo();

   //destroy方法用于在Servlet销毁(一般指关闭服务器)时释放一些资源,也只会调用一次。
   public void destroy();
}

 

   1.1init方法:

    init方法被调用时会接受到一个ServletConfig(Servlet的配置)类型的参数,是容器传进去的。我们在web.xml中定义Servlet时通过init-param标签配置的参数就是通过ServletConfig来保存的。

  1.2 getServletConfig 方法:

  1.3 service方法:

  1.4 getServletInfo方法:

  1.5 destroy方法:

 

二、ServletConfig接口:

  ServletConfig接口的定义如下:

public interface ServletConfig {

    //获取Servlet的名字,也就是在web.xml中定义的servlet-name
    public String getServletName();

    //返回的ServletContext代表着我们这个应用本身。其实就是Tomcat中Context的门面类ApplicationContextFacade。
    public ServletContext getServletContext();

    //用于获取init-param配置的参数
    public String getInitParameter(String name);

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

 

   其中方法getServletContext返回值ServletContext代表了应用本身,所以ServletContext里边设置的参数就可以被当前应用的所有的Servlet所共享。

  我们做项目的时候都知道参数可以保存在session中,也可以保存在application中,而servlet的参数就是保存在servletContext中。

  可以这么理解,ServletConfig是Servlet级的,ServletContext是Context级的。当然ServletContext的功能非常强大,不只是保存配置参数。

  在ServletContext的接口中有一个方法:public Servlet getContext(String uripath),它可以根据路径获取到同一个站点下的别的应用的ServletContext,由于安全的原因,一般返回的是null。

三、GenericServlet抽象类:

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

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

    1.实现了ServletConfig的接口。

      我们可以直接调用ServletConfig里面的方法。因此当我们需要获取ServletContext时就可以直接调用getServletConfig(),而不用调用getServletConfig().getServletContext()了。

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

      GenreicServlet实现了Servlet的init(ServletConfig config)方法,将里面的config赋值给了自身的内部变量config,然后调用了无参的init方法,这个无参的init()方法是个模板方法,可以在子类中通过覆盖它来完成自己的初始化工作。

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

 

    3.提供了两个log方法。

      一个是记录日志,一个是记录异常。

//记录日志   
 public void log(String msg) {
        getServletContext().log(getServletName() + ": " + msg);
    }
//记录异常
    public void log(String message, Throwable t) {
        getServletContext().log(getServletName() + ": " + message, t);
    }

 

  一般我们都是有自己的日志处理方式,所以用的不多。而且GenreicServlet是与具体协议无关的。

 

四、HttpServlet抽象类:

  HttpServlet使用HTTP协议实现的Servlet的基类,因此在我们写Servlet的时候直接继承HttpServlet就可以了。Spring MVC中的DispatcherServlet就是继承的HttpServlet。

  因为是和协议相关的,所以这里就比较关心请求的事情了。在HttpServlet中主要重写了service方法,将父类中(Servlet接口)service方法的参数ServletRequest和ServletResponse转换为HttpServletRequest和HttpServletResponse。

//重写父类的方法    
@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");
        }
        //调用本类中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 {
            //
            // 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);
        }
    }

 

   这里只是将Servlet中的一些源码做些分析。

以上是关于servlet-servlet的简单认识的主要内容,如果未能解决你的问题,请参考以下文章

代码片段 - Golang 实现简单的 Web 服务器

创建自己的代码片段(CodeSnippet)

简单的方法来分享/讨论/协作的代码片段?

java 简单的代码片段,展示如何将javaagent附加到运行JVM进程

python 用于在终端中运行的sublime text 3的简单代码片段制作工具

在android中显示隐藏片段