servlet相关类的简单总结(3.1.0版本)

从实习开始,就开始使用spring的框架进行开发,一直没琢磨过servlet,框架用的多了,底下的东西就越来越不了解了,今天简单总结一下servlet。先看下java本身提供的几个接口和类,下面是继承关系:

一、继承关系

servlet相关类的简单总结(3.1.0版本)_第1张图片

二、servlet源码

public interface Servlet {

    public void init(ServletConfig config) throws ServletException;
    
    public ServletConfig getServletConfig();
    
    public void service(ServletRequest req, ServletResponse res)
	throws ServletException, IOException;
	
	public String getServletInfo();

    public void destroy();

方法解释:
从servlet源码可以看出接口内一共有六个方法,接下来看一下没个方法的作用:

  1. init方法是当servlet加载的时候由servlet容器调用的方法,参数为ServletConfig ,也就是servlet的配置。顺便解释一下,当我们的web程序启动的时候,当servlet容器(如:tomcat)接收到第一个客户端的请求的时候,就会调用这个init方法来初始化一个servlet实例,但是仅限于第一次,这个servlet实例一旦被创建,除非结束程序调用下面的destroy方法,否则这个servlet实例就会一直存在。以后当再有请求进入的时候,使用的还是当前这个servlet实例。
  2. getServletConfig方法是用来获取我们的servlet配置的方法,源码如下:
public interface ServletConfig {
   
    public String getServletName();

    public ServletContext getServletContext();

    public String getInitParameter(String name);

    public Enumeration<String> getInitParameterNames();
}
  1. 通过源码我们可以看到获取到的就是servlet的配置信息,包括我们配置servlet时指定的名字(下面配置文件中的中的值)。servlet上下文(servlet初始化实例后会把一些公共的信息放在servletContext中,也叫servlet作用域)。根据名字(下面配置文件中的)获取到我们在web.xml中配置的初始化参数(下面配置文件中的)以及最后的获取到所有初始化参数的名字(下面配置文件中的)。具体name和初始化参数是什么,我们举个例子:
<servlet>
		<servlet-name>JerseyServlet</servlet-name>
		<servlet-class>
			com.xxx.MatrixServlet
		</servlet-class>
		<init-param>  
          		<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>  
          	 	 <param-value>com.xxxx.InternalAuthResourceFilter</param-value>  --> 
         </init-param>
         <init-param> 
        	 	<param-name>com.sun.jersey.spi.container.ResourceFilters</param-name>
         		<param-value>com.xxxx.RoleApiResourceFilterFactor</param-value>
    	</init-param>
</servlet>
  1. service方法是servlet中最重要的一个方法,这是真正处理请求的方法,当servlet实例初始化完成之后,每一个请求都会实际调用这个方法来处理请求。该方法中有两个参数ServletRequest req, ServletResponse res,这两个参数也是servlet容器在调用这个方法的时候传入进来的,一个是请求信息,另一个是响应。这两个对象的方法中就是获取的请求和响应的一些东西,具体是什么点进去看看就大概知道了,比如:编码方式,请求参数等等。具体再单独写一篇介绍吧。现在主要介绍servlet相关的几个方法。
  2. getServletInfo方法顾名思义就是来获取servlet的信息的,比如作者版本著作权之类的信息。
  3. destroy方法是程序结束时调用的方法,用来摧毁servlet实例的。

三、GenericServlet部分源码

public String getInitParameter(String name) {
        ServletConfig sc = getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(
                lStrings.getString("err.servlet_config_not_initialized"));
        }

        return sc.getInitParameter(name);
}
public Enumeration<String> getInitParameterNames() {
        ServletConfig sc = getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(
                lStrings.getString("err.servlet_config_not_initialized"));
        }

        return sc.getInitParameterNames();
}
public ServletContext getServletContext() {
        ServletConfig sc = getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(
                lStrings.getString("err.servlet_config_not_initialized"));
        }

        return sc.getServletContext();
}
public void init(ServletConfig config) throws ServletException {
	this.config = config;
	this.init();
}
public void init() throws ServletException {

}
public String getServletName() {
        ServletConfig sc = getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(
                lStrings.getString("err.servlet_config_not_initialized"));
        }

        return sc.getServletName();
}

源码解析:因为GenericServlet是servlet的抽象实现类,所以脸面实现了servlet的部分方法,入上源码罗列出来了一部分。我们主要关注init方法:

  1. 通过源码我们可以看出,GenericServlet实现了servlet的init方法主要做了两件事,第一给servletConfig初始化,然后调用另一个空的init方法。为什么这么做呢?
  2. 这么做的目的就是我们不需要再去维护这个servletConfig属性,我们只需要关注自己的业务代码就好了,我们继承GenericServlet这个类后,只需要实现他的init方法就可以了,不需要再去维护servletConfig属性了,这就简化了我们开发时候的一些负担。

四、HttpServlet部分源码

    @Override
    public void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException
    {
        HttpServletRequest  request;
        HttpServletResponse response;
        
        if (!(req instanceof HttpServletRequest &&
                res instanceof HttpServletResponse)) {
            throw new ServletException("non-HTTP request or response");
        }

        request = (HttpServletRequest) req;
        response = (HttpServletResponse) res;

        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 = req.getDateHeader(HEADER_IFMODSINCE);
                if (ifModifiedSince < lastModified) {
                    // 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);
        }
}

源码解析:
同样HttpServlet类继承了GenericServlet抽象类,通过我们上面说的知道,我们只需要实现service方法就可以了。那么既然我们实现GenericServlet类的init方法就可以了,为什么还要HttpServlet类去实现他呢?看下源码:

  1. 通过源码我们可以看出来HttpServlet的service方法把servletRequest和servletResponse转化成了HttpServletRequest和HttpServletResponse,至于这两个又是什么,同样和上面的servletRequest和servletResponse一起在另一篇讨论。主要接下来执行的service方法。
  2. 这个service方法我们可以看到,就是对请求方式做了判断,从而去执行对应的doXxxx方法,而对应的doXxxx方法又只是对请求协议的一个简单判断,那么为什么这样设计呢?
  3. 这样设计的好处就是当我们再想实现一个servlet时,只需要继承HttpServlet这个类,然后根据请求方式去实现具体的doXxxx方法就可以了,一般doGet和doPost居多。这样是不是就更精细的控制了。

五、总结

通过上面的简单分析,我们的大概知道了servlet几个类和接口之间的关系了:

  1. 首选要实现一个servlet就必须实现servlet接口,这样servlet容器就会执行init方法。
  2. 而这个init方法又交给了GenericServlet类来执行,帮我们维护了servletConfig这个参数。
  3. 而HttpServlet继承了GenericServlet后,又帮我们实现了一部分service方法,使得我们可以根据自己的请求方式自定义的去实现对应的doXxxx方法。
  4. 最后servlet实例被销毁后执行destroy方法,这是一个大致的servlet实例的生命周期过程,具体细节需要再琢磨了。

至此这几个java自带的servlet类关系就差不多了。

你可能感兴趣的:(java,Java,源码)