Servlet的一些重要细节

来源:互联网 发布:tgp腾讯游戏客户端mac 编辑:程序博客网 时间:2024/05/17 06:15

1、javax.servlet.Servlet接口中的生命周期方法(即回调函数,由服务器自动调用)

  • init(ServletConfig config)
  • service(ServletRequest request,ServletResponse response)
  • destroy()   

请注意格式,如在GenericServlet类中定义的init( )方法则不是生命周期方法。


2、Servlet执行过程

默认情况下,服务器会在Servlet第一次被访问时创建Servlet(你也通过修改web.xml中的配置,让服务器在启动的时候就创建出Servlet)。并且一个Servlet类型是单例的,服务器会通过反射机制创建一个实例对象这就会导致线程不安全问题)。在Servlet被创建之后,服务会立即调用init(ServletConfig config)方法(只会调用一次),服务器接着会调用service(ServletRequest request, ServletResponse response)方法来处理用户的请求,以及服务器做出响应。一般Servlet不会轻易被销毁,当服务器被关闭了,才会销毁Servlet,并在这之前服务器会调用destroy( )方法

由于Servlet采用单例模式,我们第二次或以后再访问Servlet时,服务器会直接调用Service(ServletRequest request, ServletResponse response)方法。服务器接收到一次请求,就会调用service()方法一次,所以service()方法是会被调用多次的。


3、Servlet各种实现的关联

----- HttpServlet 类继承了 GenericServlet类

----- GenericServlet 类实现了 Servlet 接口

3.1 、 GeneicServlet类源码解读

package javax.servlet;import java.io.IOException;import java.util.Enumeration;public abstract class GenericServlet implements Servlet, ServletConfig,        java.io.Serializable {    private transient ServletConfig config;     //用来实现getServletConfig();    public GenericServlet() {          // NOOP    }    public void destroy() {        // NOOP by default    }    public String getInitParameter(String name) {       //ServletConfig中定义的方法        return getServletConfig().getInitParameter(name);    }    public Enumeration<String> getInitParameterNames() {          return getServletConfig().getInitParameterNames();    }    public ServletConfig getServletConfig() {        return config;    }    public ServletContext getServletContext() {           <span style="font-family: Arial, Helvetica, sans-serif;">//ServletConfig中定义的方法</span>        return getServletConfig().getServletContext();    }    @Override    public String getServletInfo() {        return "";    }    public void init(ServletConfig config) throws ServletException {        this.config = config;        this.init();    }    public void init() throws ServletException {      //GenericServlet自己定义的方法,由于声明周期方法init(ServletConfig config)中调用了该方法,所以初始化的时候该方法也会自动被调用。    }    public void log(String msg) {        getServletContext().log(getServletName() + ": " + msg);    }    public void log(String message, Throwable t) {        getServletContext().log(getServletName() + ": " + message, t);    }    public abstract void service(ServletRequest req, ServletResponse res)    //需要子类自行实现该方法            throws ServletException, IOException;    public String getServletName() {        return config.getServletName();    }}

我们可以看到GenericServlet是一个抽象类(service是抽象方法,要我们继承的时候自己写实现方法。),并且同时还实现了ServletConfig接口。

当我们自定义Servlet时,如果想完成初始化作用就不要再重复init(ServletConfig)方法了,而是应该去重写init()方法。因为在GenericServlet中的init(ServletConfig)方法中保存了ServletConfig对象,如果覆盖了保存ServletConfig的代码,那么就不能再使用ServletConfig了。也就是说GenericServlet的实例变量config的值为null,那么所有依赖config的方法都不能使用了。

3.2、HttpServlet类的理解

HttpServlet类是在GenericServlet类的基础之上,再提供了对HTTP请求的特殊支持,所以我们在写自己的Servlet的时候一般都是继承HttpServlet。

· 在上面我们看到GenericServlet类是一个抽象类,要继承它必须实现service(ServletRequest request, ServletResponse response)方法。而在HttpServlet类中service(ServletRequest request, ServletResponse response)是这样实现的:

@Override    public void service(ServletRequest req, ServletResponse res)        throws ServletException, IOException {        HttpServletRequest  request;        HttpServletResponse response;        try {            request = (HttpServletRequest) req;              //将<span style="font-family: Arial, Helvetica, sans-serif;">request强转成HttpServletRequest </span>            response = (HttpServletResponse) res;        } catch (ClassCastException e) {            throw new ServletException("non-HTTP request or response");        }        service(request, response);                         //在声明周期方法中调用service(HttpServletRequest req, HttpServletResponse resp)方法    }


service(HttpServletRequest req,HttpServletResponse resp)方法的定义:

 protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {    String method = req.getMethod();         //先获取客户端的请求方法,然后再判断,调用相应的方法。        if (method.equals(METHOD_GET)) {.....            doGet(req, resp);......        } 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);        }    }


4、Servlet线程安全

我们不应该在Servlet中便宜创建成员变量,因为可能会存在一个线程对这个成员变量进行写操作,另一个线程对这个成员变量进行读操作。

只要保证没有共享的域就保证Servlet的线程线程安全,一般有如下的措施:

  • 不要在Servlet中创建成员变量!创建局部变量即可;
  • 可以创建没有成员变量的类作为Servlet的成员变量;
  • 作为Servlet类成员变量的类可以有成员变量,但是其成员变量必须是只读的;
5、获取初始化参数

l  Servlet也可以获取初始化参数,但它是局部的参数;也就是说,一个Servlet只能获取自己的初始化参数,不能获取别人的,即初始化参数只为一个Servlet准备!

ServletConfig中的getInitParameter(String name)方法

其初始化参数在web.xml中配置如下:

  <servlet>    <servlet-name>FileuploadServlet</servlet-name>    <servlet-class>cn.edu.jxau.servlet.FileuploadServlet</servlet-class> <init-param> <param-name>aaa</param-name> <param-value>AAA</param-value> </init-param>  </servlet>

l  可以配置公共的初始化参数,为所有Servlet而用!这需要使用ServletContext才能使用!

ServletContext中的getInitParameter(String name)方法

 <display-name></display-name>  <context-param>  <param-name>aaa</param-name>  <param-value>AAA</param-value>  </context-param>  <servlet>    <servlet-name>FileuploadServlet</servlet-name>    <servlet-class>cn.edu.jxau.servlet.FileuploadServlet</servlet-class>  </servlet>









0 0