JavaWeb --- Servlet、Filter、Listener的理解(Servlet篇)

Javaweb主要组件Servlet、Filter、Listener

1.Servlet

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

1. 什么是Servlet?
  Servlet就是一个java接口,处理请求和发送响应的过程是由一种叫做Servlet的程序来完成的,并且Servlet是为了实现动态页面而衍生的东西。

2. Tomcat和Servlet的关系
Tomcat和Servlet的关系图

  ①处表示Web服务器接收到客户端发出的HTTP请求后,转发给Servlet容器,同时把控制返回Servlet容器;
  ②处表示Servlet容器把响应对象ServletResponse中的处理结果转发给Web服务器,通知Web服务器以HTTP响应的方式把结果发送到客户端,同时把控制返回Web服务器

  Tomcat是Web应用服务器,是一个servlet/Jsp容器,Tomcat 作为Servlet容器,它监听了端口负责处理客户请求,把请求传送给Servlet,并将Servlet的响应传送回给客户。
  Java Servlet API是Servlet容器和Servlet之间的接口,它定义了Servlet的各种方法,还定义了Servlet容器传送给Servlet的对象类,其中最重要的是请求对象ServletRequest和响应对象ServletResponse这两个对象都是由Servlet容器在客户端调用Servlet时产生的,Servlet容器把客户请求信息封装在ServletRequest对象中,然后把这两个对象都传送给要调
用的Servlet,Servlet处理完后把响应结果写入ServletResponse,然后由Servlet容器把响应结果发送到客户端。

3. 创建Servlet的原理

  1. Servlet的生命周期
      在web.xml<servlet>中添加一条配置信息<load-on-startup>5</load-on-startup>(默认为0),当值大于0时,容器在应用启动时就会初始化一个servlet对象,当是一个负数时或者没有指定时,则指示容器在该servlet被请求时才加载,也就是会执行初始化方法init(ServletConfig conf)。
      最后服务器关闭时,才会销毁这个servlet对象,执行destroy()方法。
      PS:Servlet是单例的,整个服务器就只创建一个同类型Servlet;
  2. HttpServlet与Servlet
    查看源码,httpServlet继承了GenericServlet

    public abstract class HttpServlet extends GenericServlet

    GenericServlet的继承结构,实现了Servlet接口和ServletConfig接口

    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 String getInitParameter(String name) {
        return getServletConfig().getInitParameter(name);
    }
    
    @Override
    public Enumeration<String> getInitParameterNames() {
        return getServletConfig().getInitParameterNames();
    }
    
    @Override
    public ServletConfig getServletConfig() {
        return config;
    }
    
    @Override
    public ServletContext getServletContext() {
        return getServletConfig().getServletContext();
    }
    
    @Override
    public String getServletInfo() {
        return "";
    }
    
    @Override
    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }
    
    public void init() throws ServletException {
        // NOOP by default
    }
    
    public void log(String msg) {
        getServletContext().log(getServletName() + ": " + msg);
    }
    
    public void log(String message, Throwable t) {
        getServletContext().log(getServletName() + ": " + message, t);
    }
    
    @Override
    public abstract void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException;
    
    @Override
    public String getServletName() {
        return config.getServletName();
    }

    ServletConfig接口的代码

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

    由Servlet接口方法可以看到,Servlet三个关键方法init()、service()、destroy(),其他两个方法:
      一个是getServletConfig(),是获取ServletConfig对象,ServletConfig对象可以获取到Servlet的一些信息,包含ServletName、ServletContext、InitParameter、InitParameterNames等(WEB-INF目录下的web.xml中的servlet标签里面的信息)。

    其中ServletContext对象是servlet上下文对象,代表当前Web应用,并且它被所有客户端共享

      另一个是getServletInfo(),是返回一个String类型的字符串,其中包括了关于Servlet的信息,例如作者、版本和版权。
      GenericServlet实现了Servlet接口后,我们可以直接继承GenericServlet,就可以使用上面我们所介绍Servlet接口中的那几个方法了,能拿到ServletConfig,继而获取ServletContext,为了方便GenericServlet除了实现Servlet接口外,还实现了ServletConfig接口,就可以直接获取ServletContext了。
      GenericServlet 中有两个init()方法原因:见Servlet详解之两个init方法的作用

  3. Service方法的执行

    public abstract class GenericServlet implements Servlet, ServletConfig,
    java.io.Serializable {
    
        @Override
        public abstract void service(ServletRequest req, ServletResponse res)
                throws ServletException, IOException;
    }

    查看GenericServlet的service()方法,它是一个抽象方法,实际上HttpServlet类继承了GenericServlet,它主要是实现service()方法的细节。
    查看HttpServlet的代码

    public abstract class HttpServlet extends GenericServlet {
    
        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);
            }
        }    
    
        @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);
        }
    }

    查看HttpServletRequest的代码

     public interface HttpServletRequest extends ServletRequest

      因此可以看到下边的service(ServletRequest req, ServletResponse res)方法主要是将ServletRequestServletResponse强制转换为了HttpServletRequest和HttpServletResponse,再调用service(HttpServletRequest req, HttpServletResponse resp)方法,这个方法就是判断浏览器过来的请求方式是get还是post然后分别执行doGet()或doPost()方法,我们写的Servlet集成HttpServlet后,就只要重写doGet()和doPost()方法,而不用直接重写service()方法了,简便了开发。

猜你喜欢

转载自blog.csdn.net/mxjesse/article/details/80317125