`
he_wen
  • 浏览: 234510 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

servlet源码和生命周期

    博客分类:
  • Java
阅读更多

这里是servlet的类图之间的设计关系,里面接口、抽象类我只写上关键的方法让大家参考:



 

下面根据类图关系和servlet的生命周期讲解:

一、servlet容器(如tomcat)加载servlet类,读入其.class类文件到内存
二、servlet容器开始针对这个servlet,创建ServletConfig对象(他的主要任务就是读取配置文件的相关信息,想我们写一个Servlet时,就要配置.XML文件,指定自己的Servlet在哪个地方,还有是否经过过滤器等等)
三、 servlet容器创建servlet对象4. servlet容器调用servlet对象的init(ServletConfig config)方法,在这个init方法中,建立了sevlet对象和servletConfig对象的关联,执行了如下的代码:
 
 

public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init(); //调用了无参的 init()方法 
    }
    /***
     *     无参的init()方法
     * @throws ServletException
     */
    public void init() throws ServletException {

    }

    public void init(ServletConfig config) throws ServletException
    {  
      this.config = config;  //将容器创建的servletConfig 对象传入,并使用私有成员变量引用该servletConfig对象  
      this.init();   
    }
 //获取初始化参数 
    public String getInitParameter(String name) {
        return getServletConfig().getInitParameter(name);
    }

    //实现了接口<ServletConfig>中的方法,用于返回在web.xml文件中为servlet所配置的全部的初始化参数的值 
    public Enumeration getInitParameterNames() {
        return getServletConfig().getInitParameterNames();
    }

    //获取在web.xml文件中注册的当前的这个servlet名称。没有在web.xml 中注册的servlet,该方法直接放回该servlet的类名。 
    //法实现了接口<ServleConfig>中的getServletName方法   
    public String getServletName() {
        return config.getServletName();
    }

public ServletContext getServletContext() {
        return getServletConfig().getServletContext();
    }
 有的人会问设计者为什么要写两个init()方法呢?
这是因为这里的config对象的引用就来自Init(ServletConfig config)执行的结果.
所以如果子类需要覆盖了父类的init(ServletConfig config)方法,则首先要调用父类的init(ServletConfig config)方法,也就是先加入 super.init(config) 语句来先执行父类的方法.否则,会产生空指针异常 java.lang.NullPointerException ,因为config对象的引用为空。
 
为了避免这样的情况的产生,GenericServlet的设计人员 在GenericServlet中又定义了一个无参数的init()空方法. 且在init(servletConfig config)方法最后也调用了这个无参的空方法
Java代码
public void init(ServletConfig config) throws ServletException 

    this.config=config; 
    init();      

public void init(ServletConfig config) throws ServletException
{
    this.config=config;
    init();    
}
所以,我们只需覆盖这个无参的init方法加入自己的初始代码即可,而无需覆盖带参数的父类的init方法.如果有多个重载的init方法,对以servlet而言,servlet容器始终就之调用servlet接口中的那个方法:init(ServletConfig config) (当然也会执行已经覆盖的无参的init()方法),其他的覆盖的init方法不会执行。
通过以上的初始化步骤建立了servlet对象和sevletConfig对象的关联,而servletConfig对象又和当前容器创建的ServleContext对象获得关联.
 
五、运行时阶段当容器接受到访问特定的servlet请求时,针对这个请求,创建对应的ServletRequest对象和 ServletResponse对象,并调用servlet的service()方法,service()根据从ServletRequest对象中获得 客户的请求信息并将调用相应的doxxx方法等进行响应,再通过ServletResponse对象生成响应结果,然后发送给客户端,最后销毁创建的ServletRequest 和ServletResponse
在抽象类中GenericServlet中service()是一个抽象方法,但在HttpServlet中对这个方法进行了实现。servlet 接口中定义的service()方法中的两个参数分别是servletRequest 和 ServletResponse 这两个类型。当前的http请求,如果需要在这个service()方法内部使用http消息特有的功能,也就是要调用 HttpServletRequest 和HttpServletResponse来中定义的方法时,需要将请求和响应对象进行一个类型的转换,所以,在GenericServlet中,使用了 两个方法来共同完成这个工作。
实现父类GenericServlet中的service(ServltRequest req,ServeltResponse res)抽象方法
为什么在Servlet中的service方法?
service(ServletRequest servletrequest, ServletResponse servletresponse)
而不是用HttpServletRequest和HttpServletResponse呢?这是因为这样定义就与应用层的任何协议没有任何关系.在HttpServlet重载service()这样就可以向下转型。查看源代码
相应的Java代码:
/**
   * 通过参数的向下转型,然后调用重载的
     */
    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);
    }
    protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String method = req.getMethod();
        if(method.equals("GET"))
        {
            long lastModified = getLastModified(req);
            if(lastModified == -1L)
            {
                doGet(req, resp);
            } else
            {
                long ifModifiedSince = req.getDateHeader("If-Modified-Since");
                if(ifModifiedSince < (lastModified / 1000L) * 1000L)
                {
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else
                {
                    resp.setStatus(304);
                }
            }
        } else
        if(method.equals("HEAD"))
        {
            long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);
        } else
        if(method.equals("POST"))
            doPost(req, resp);
        else
        if(method.equals("PUT"))
            doPut(req, resp);
        else
        if(method.equals("DELETE"))
            doDelete(req, resp);
        else
        if(method.equals("OPTIONS"))
            doOptions(req, resp);
        else
        if(method.equals("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(501, errMsg);
        }
        }
六、、销毁阶段:只有当web应用被终止时,servlet才会被销毁。servlet容器现调用web应用中所有的Servlet对象的 destroy()方法,然后再销毁这些servlet对象,此外,容器还销毁了针对各个servlet所创建的相关联的serveltConfig对象
注意在Servlet生命周期中init()和destory()方法只调用一次,是单列模式

  • 大小: 140.4 KB
1
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics