`

Servlet框架基础和生命周期(结合源码)

阅读更多
 

Servlet框架基础和生命周期(结合源码)、destroy()的思考

  前言

                 Servlet是一个java编写的程序,此程序是在服务器端运行的,是按照Servlet规范编写的一个

             java类。Servlet是处理客户端的请求,并将处理结果以响应的方式返回给客户端。Servlet框架

             是怎样的呢?它的生命周期又是什么情况呢?这是本文需要探求的。

         Servlet框架

                 网上下载Servlet源码,解压之后发现其由两个包组成:

                         1、javax.servlet

                         2、javax.servlet.http

            javax.servlet

                  此包中定义了所有Servlet类都必须实现的接口或类。

                  接口定义:

                  ServletConfig接口---在初始化过程中由Servlet容器(Tomcat调用)

                  ServletContext接口---定义Servlet用于获取容器信息的方法

                  ServletRequest接口---向服务器请求信息

                  ServletResponse接口 ---响应客户端请求

                  Servlet接口---定义所有的Servlet必须实现的方法

                  类定义:

                  ServletInputStream类 --- 用于从客户端读取二进制数据

                  ServletOutputStream类 ---用于将二进制数据写入到客户端

                  GenricServlet--- 抽象类,定义一个通用的,独立于底层协议的servlet。

            java.servlet.http

                  此包中定义了使用HTTP通信协议的所有Servlet类应该实现的类、接口。

                  接口定义:

                   HttpServletRequest接口 --- 封装http请求

                   HttpServletResponse接口 --- 封装http响应

                   HttpSession接口 --- 用于表示客户端存储有关客户的信息

                   HttpSessionAttributeListener接口---实现这个监听接口,当用户获取Session的属性列表发生

                                                             改变的时候得到通知。

                   类的定义:

                   HttpServlet类 --- 扩展了GenericServlet的抽象类

                   Cookie类 --- 创建一个Cookie,Cookie技术,用户存储服务器发送给客户端的信息。

               通过阅读Servlet框架源码,其主要的框架结构如下图:

               

             Servlet工作过程

                        通过上述Servlet框架的了解我们可以初步描述一下Servlet在Tomcat容器中是如何工作的。

                   来看下面的时序图:

                 

                    1、Web Client 向Servlet容器(Tomcat)发出Http请求

                    2、Servlet容器接收Web Client的请求


                    3、Servlet容器创建一个HttpRequest对象,将Web Client请求的信息封装到这个对象中

                    4、Servlet容器创建一个HttpResponse对象

                    5、Servlet容器调用HttpServlet对象的service方法,把HttpRequest对象与HttpResponse

                        对象作为参数传给 HttpServlet对象

                   6、HttpServlet调用HttpRequest对象的有关方法,获取Http请求信息

                   7、HttpServlet调用HttpResponse对象的有关方法,生成响应数据

                   8、Servlet容器把HttpServlet的响应结果传给Web Client

                Tomcat和HttpServlet是如何进行交互的呢?从源码中我们可以得到

                 

            Servlet生命周期

                       在Servlet框架中所有的Servlet类都必须实现Servlet这个接口。其中定义了三个方法:

                            1、init方法:负责初始化Servlet对象。

                            2、service方法:用于响应客户端的请求

                            3、destroy:销毁Servlet对象,释放占用的资源。

                       Servlet生命周期四个阶段:

                             ●  加载阶段:加载并实例化(创建Servlet实例)

                             ●  初始化阶段:调用init()方法

                             ●  响应客户请求阶段:调用service()方法,doGet、doPost

                             ●  终止阶段:调用destroy()方法

                            

                  加载阶段

                       Tomcat从文件系统,远程文件系统或其他网络服务中通过类加载器来加载Servlet,并调用

                   Servlet的默认构造方法(不带参构造器)

                  初始化阶段init()方法

                       当Servlet容器启动时:读取web.xml配置文件中的信息,构造指定的Servlet对象,根据配置

                    文件的信息创建ServletConfig对象,并将其作为参数传递给init方法进行调用。

                       Tomcat启动后:用户首次想某个Servlet对象发送请求,Tomcat会判断内存中是否存在指定的

                     servlet对象,如果没有则会去创建它,然后创建HttpRequest,HttpResponse对象,调用service

                    方法处理用户的请求。

                       从Servlet的构造开始我们没有显示的看到init()方法的调用,那么init方法到底是何时进行调用

                    的呢?阅读源码可以知道:init方法是在实例化Servlet之后调用的,其参数ServletConfig是在

                    Servlet初始化阶段Tomcat根据web.xml配置信息,和操作系统的相关环境生成并传递给init

                    方法的。         

[java] view plain copy
 
  1. * Called by the servlet container to indicate to a servlet that the   
  2.      * servlet is being placed into service.  
  3.      *  
  4.      * <p>The servlet container calls the <code>init</code>  
  5.      * method exactly once after instantiating the servlet.  
  6.      * The <code>init</code> method must complete successfully  
  7.      * before the servlet can receive any requests.  
  8.      *  
  9.      * <p>The servlet container cannot place the servlet into service  
  10.      * if the <code>init</code> method  
  11.      * <ol>  
  12.      * <li>Throws a <code>ServletException</code>  
  13.      * <li>Does not return within a time period defined by the Web server  

 

 

[java] view plain copy
 
  1. /** 
  2.  *  
  3.  * A servlet configuration object used by a servlet container 
  4.  * to pass information to a servlet during initialization.  
  5.  * 
  6.  */  
  7.    
  8. public interface ServletConfig {  

 

               响应客户请求阶段service方法

                     service()方法是在客户端第一次访问servlet时执行的,其实init方法同样也是在有客户端访问

                 servlet的时候才被调用。不过需要特别注意的是讨论init方法在session级别上时,当存在不同的

                 会话访问相同的servlet时,Tomcat会开启一个线程处理这个新的会话,但是此时Tomcat容器

                 不会实例化这个servlet对象,也就是有多个线程在共享这个servlet实例。换句话说Servlet对象在

                 servlet容器中是以单例的形式存在的!然而查看其源码可以发现,Servlet在多线程下并未使用同

                 步机制,因此,在并发编程下servlet是线程不安全的

                       对于Servlet的并发,线程安全的处理问题,笔者会找个时间好好的整理下思路。

                   对于不同的session访问相同的serlvet对象,只有一次init的过程,笔者会在接下来予以演示。

                     阅读HttpServlet的源码可以知道,基于Http通信协议的HttpServlet在进行客户端响应处理的

                 时候根据客户端请求,响应的类别不同分别调用不同的方法,其中最常用的就是doGet、doPost

                 方法,这两个方法是我们在编写Servlet中的主要的逻辑处理阶段。

[java] view plain copy
 
  1.  protected void service(HttpServletRequest req, HttpServletResponse resp)  
  2. throws ServletException, IOException  
  3.    {  
  4. String method = req.getMethod();  
  5.   
  6. if (method.equals(METHOD_GET)) {  
  7.     long lastModified = getLastModified(req);  
  8.     if (lastModified == -1) {  
  9.     // servlet doesn't support if-modified-since, no reason  
  10.     // to go through further expensive logic  
  11.     doGet(req, resp);  
  12.     } else {  
  13.     long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);  
  14.     if (ifModifiedSince < (lastModified / 1000 * 1000)) {  
  15.         // If the servlet mod time is later, call doGet()  
  16.                    // Round down to the nearest second for a proper compare  
  17.                    // A ifModifiedSince of -1 will always be less  
  18.         maybeSetLastModified(resp, lastModified);  
  19.         doGet(req, resp);  
  20.     } else {  
  21.         resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);  
  22.     }  
  23.     }  
  24.   
  25. else if (method.equals(METHOD_HEAD)) {  
  26.     long lastModified = getLastModified(req);  
  27.     maybeSetLastModified(resp, lastModified);  
  28.     doHead(req, resp);  
  29.   
  30. else if (method.equals(METHOD_POST)) {  
  31.     doPost(req, resp);  
  32.       
  33. else if (method.equals(METHOD_PUT)) {  
  34.     doPut(req, resp);     
  35.       
  36. else if (method.equals(METHOD_DELETE)) {  
  37.     doDelete(req, resp);  
  38.       
  39. else if (method.equals(METHOD_OPTIONS)) {  
  40.     doOptions(req,resp);  
  41.       
  42. else if (method.equals(METHOD_TRACE)) {  
  43.     doTrace(req,resp);  
  44.       
  45. else {  
  46.     //  
  47.     // Note that this means NO servlet supports whatever  
  48.     // method was requested, anywhere on this server.  
  49.     //  
  50.   
  51.     String errMsg = lStrings.getString("http.method_not_implemented");  
  52.     Object[] errArgs = new Object[1];  
  53.     errArgs[0] = method;  
  54.     errMsg = MessageFormat.format(errMsg, errArgs);  
  55.       
  56.     resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);  
  57. }  
  58.    }  
  59.      

 

              终止阶段:destroy()方法的调用

                   上面的探讨中知道的了Servlet是如何加载、初始化、处理客户端的请求响应的,那么Servlet

               在什么时候终止呢?其生命周期又是在什么时候结束的呢?

                   我们知道的是Servlet生命周期是有Tomcat容器来管理的,由此在Tomcat关闭、或者Restart

               的时候,servlet的生命周期必然结束,destroy方法也必然被调用过。在客户端与服务器的一次

               Session会话中,session关闭之后servlet并未销毁。后续演示。

                  总的来说servlet对象什么时候destroy的呢?

                      1、Tomcat服务器stop

                      2、web项目reload

                      3、Tomcat容器所在的服务器shutdown(这不废话吗?)

            更正之处:对于destroy()方法笔者略有疑惑,“它到底是如何销毁Servlet的呢?”,基于这个问题

                 特意的去查看了源码,结果发现destroy()方法在Servlet框架中并未具体去实现。它是由Coder

             自己去实现的。因此“destroy()方法用户销毁Servlet”这种说法本身就是离谱的!查阅源码:          

[java] view plain copy
 
  1.    
  2.  /** 
  3.      * Called by the servlet container to indicate to a servlet that the 
  4.      * servlet is being taken out of service.  See {@link Servlet#destroy}. 
  5.      * 
  6.      *  
  7.      */  
  8.   
  9.  /** 
  10.      * 
  11.      * Called by the servlet container to indicate to a servlet that the 
  12.      * servlet is being taken out of service.  This method is 
  13.      * only called once all threads within the servlet's 
  14.      * <code>service</code> method have exited or after a timeout 
  15.      * period has passed. After the servlet container calls this  
  16.      * method, it will not call the <code>service</code> method again 
  17.      * on this servlet. 
  18.      * 
  19.      * <p>This method gives the servlet an opportunity  
  20.      * to clean up any resources that are being held (for example, memory, 
  21.      * file handles, threads) and make sure that any persistent state is 
  22.      * synchronized with the servlet's current state in memory. 
  23.      * 
  24.      */  
  25.   
  26.     public void destroy();  
  27. }  
           
              阅读上述注释,很明白的是destroy的调用是表明Servlet结束其servcie阶段,destroy方法的调用

 

              实际是在servlet销毁之前,由Tomcat来调用的,其作用是清理一些资源的占用情况,例如文件、

              线程,而且确保任何持久的状态和servlet的当前状态在内存中是同步的。

                   不过destroy的调用情况上述的总结是正确的。

                  也就是说Servlet的销毁时destroy()一定会被掉用,servlet方法基本是由Tomcat回调的!

              但是destroy()方法的调用只是回收一些资源,并不意味着Servlet已经销毁。至于何时销毁,这个

              笔者也不太明了,希望有人可以指出,不过据源码是Servlet结束servcie服务时销毁,Tomcat关闭

              时也会销毁。(皮之不存毛将安附焉?)

                    简单的测试下:

                      我们在doPost()方法里面简单的调用下destory方法,run项目,之后另起一个Session访问

             输出情况:

                   

              这就说明了destroy()和Servlet的销毁不存在必然联系,只是在Servlet销毁之前,destroy方法,会

               基由Tomcat回调,进行一些资源的清理,文件关闭。

          Servlet生命周期演示

                 为了更进一步的了解Servlet生命周期(它确实十分重要),笔者新建一个简单的web项目予以说明

            不当之处请指正,一起交流。

                Eclipse配合Tomcat如何新建一个web项目,这个笔者就不必多说了吧,挺简单的,网上的总结

            各式各样的也不少。不过需要注意的是高版本的Eclipse若果读者不注意的话产生的web项目是没有

             web.xml文件的,以注解的形式代替了。

              

 runtime选择自己配置好的Tomcat容器,web Module version选择2.5就可以了,不要选择3.0

这里笔者贴出项目中的一些歌主要的文件。

 web.xml配置文件。  

[html] view plain copy
 
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">  
  3.   <display-name>Servlet02</display-name>  
  4.   <welcome-file-list>  
  5.     <welcome-file>index.html</welcome-file>  
  6.     <welcome-file>index.htm</welcome-file>  
  7.     <welcome-file>index.jsp</welcome-file>  
  8.     <welcome-file>default.html</welcome-file>  
  9.     <welcome-file>default.htm</welcome-file>  
  10.     <welcome-file>default.jsp</welcome-file>  
  11.   </welcome-file-list>  
  12.   <servlet>  
  13.     <description></description>  
  14.     <display-name>HelloServlet</display-name>  
  15.     <servlet-name>HelloServlet</servlet-name>  
  16.     <servlet-class>com.kiritor.servlet.HelloServlet</servlet-class>  
  17.     <init-param>  
  18.       <description></description>  
  19.       <param-name>info</param-name>  
  20.       <param-value>this is a init message</param-value>  
  21.     </init-param>  
  22.   </servlet>  
  23.   <servlet-mapping>  
  24.     <servlet-name>HelloServlet</servlet-name>  
  25.     <url-pattern>/HelloServlet</url-pattern>  
  26.   </servlet-mapping>  
  27. </web-app>  
             注意servlet映射的配置,以及初始化参数的配置。

 

           自定义Servlet的代码:

 

[java] view plain copy
 
  1. package com.kiritor.servlet;  
  2. import java.io.IOException;  
  3. import java.io.PrintWriter;  
  4.   
  5. import javax.servlet.ServletConfig;  
  6. import javax.servlet.ServletException;  
  7. import javax.servlet.ServletRequest;  
  8. import javax.servlet.ServletResponse;  
  9. import javax.servlet.annotation.WebInitParam;  
  10. import javax.servlet.annotation.WebServlet;  
  11. import javax.servlet.http.HttpServlet;  
  12. import javax.servlet.http.HttpServletRequest;  
  13. import javax.servlet.http.HttpServletResponse;  
  14.   
  15.   
  16. public class HelloServlet extends HttpServlet {  
  17.     private static final long serialVersionUID = 1L;  
  18.   
  19.     /** 
  20.      * Default constructor.  
  21.      */  
  22.     public HelloServlet() {  
  23.       super();  
  24.     }  
  25.   
  26.     @Override  
  27.     public void init(ServletConfig config) throws ServletException {  
  28.         // TODO Auto-generated method stub  
  29.         super.init(config);  
  30.         System.out.println("init方法被执行");  
  31.         System.out.println("相关的初始化参数:");  
  32.         System.out.println(config.getInitParameter("info"));  
  33.     }  
  34.     /** 
  35.      * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) 
  36.      */  
  37.     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
  38.       this.doPost(request, response);  
  39.     }  
  40.   
  41.     /** 
  42.      * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) 
  43.      */  
  44.     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
  45.        PrintWriter printWriter = response.getWriter();  
  46.        printWriter.write("Hello world");  
  47.     }  
  48.   @Override  
  49.   protected void service(HttpServletRequest arg0, HttpServletResponse arg1)  
  50.         throws ServletException, IOException {  
  51.       super.service(arg0, arg1);  
  52.       System.out.println("service方法被执行");  
  53.  }  
  54.   @Override  
  55. public void destroy() {  
  56.     super.destroy();  
  57.     System.out.println("destroy方法被执行");  
  58. }  
  59.   
  60. }  
                  接下来我们直接run该项目。看看后台输出结果,现在貌似可以直接在Eclispe控制台查看

 

             输出信息了,十分方便。

                

                 init方法是在servlet实例化后由Tomcat容器进行调用的,生成了诸多信息,其中包含我们自己

            定义的Servlet配置信息,在init方法中我们通过ServletConfig对象获取到了。

                 之后service方法执行了。这里新开启一个session会话,看看情况。图我就不贴了,控制台

            多输出一句service被执行。证明了servlet在容器中实例单例的形式存在。源码层面上Servlet不是

            单例的,只是由于容器对其的维护,使之产生了类似单例的效果。

                 接下来我们看destroy方法的调用情况,只是针对上述两种情况来说的,不可能笔者还去关机‘

            演示。首先我们关闭Tomcat服务器

                

               之后再Tomcat主页webapp管理上演示下reload,由于我们需要对Tomcat进行管理,我们将项目

           打成war,单独运行Tomcat并发布war进行测试。

              

              

             点击reload查看后台输出结果

            

                  对Servlet生命周期的问题就总结到这里了,笔者上述中有什么问题或者错误的地方希望读者给予

            指正,大家多多交流。

                  对于Servlet的线程安全问题笔者会找个时间在学习下。

 

教程推荐:http://blog.csdn.net/lcore/article/details/8967528

分享到:
评论

相关推荐

    Servlet框架基本源码

    总结,Servlet框架是Java Web开发的基础,理解其源码和工作原理对于构建高效、稳定的Web应用至关重要。通过MyEclipse等IDE,我们可以快速地搭建和调试Servlet应用,进一步提升开发效率。在实际项目中,结合MVC模式和...

    servlet的架构与生命周期

    同时,使用日志框架(如Log4j或SLF4J)可以记录Servlet的生命周期事件,便于追踪和诊断问题。 总结,Servlet是Java Web开发的核心,理解其架构和生命周期对于编写高效、稳定的Web应用程序至关重要。通过深入学习...

    《Servlet和JSP学习指南》源码

    10. **MVC框架与Servlet/JSP结合**:Spring MVC、Struts2等框架整合了Servlet和JSP,提供了更高级的结构和功能,如依赖注入、AOP等,提高了开发效率和应用性能。 这份源码将帮助读者理解Servlet和JSP的内部工作原理...

    《Jsp&Servlet入门级项目全程实录》源码

    Servlet生命周期包括加载、初始化、服务、销毁等阶段。源码中的Servlet类将展示如何处理请求和响应,以及如何在服务器上管理会话状态。 3. **JSP与Servlet交互**:在实际项目中,JSP通常用于视图层,而Servlet用于...

    servlet-api源码包

    Servlet-API是Java Web开发中的核心组件,主要用于处理HTTP请求和响应。这个源码包包含了用于构建动态Web应用程序的...在实际开发中,结合Java的MVC框架(如Spring MVC)和其他库,可以构建出高效、可扩展的Web系统。

    servlet源码 servlet-api-src javax.servlet.Servlet源码

    通过阅读源码,我们可以理解Servlet API的工作机制,了解请求和响应对象的内部实现,以及容器如何管理Servlet的生命周期。这对于优化性能、调试问题以及自定义Servlet行为都非常有帮助。 在实际开发中,我们通常...

    javax-servlet源码包和jar文件

    这次提供的压缩包包含了这两个包的源码和jar文件,对于学习和理解Servlet的工作原理非常有帮助。 1. **Servlet API**: `javax.servlet` 包含了Servlet和Filter的核心接口和类,如`Servlet`, `GenericServlet`, `...

    纯servlet+jsp后台管理 无任何框架1

    开发者需要具备扎实的Java基础知识,理解HTTP协议,熟悉Servlet和JSP的生命周期,以及一定的前端开发技能,特别是JavaScript(可能包括jQuery)。同时,由于没有使用现成的框架,开发者需要对MVC模式有深入的理解,...

    Servlet、JSP和SpringMVC初学指南源码

    Servlet生命周期包括加载、初始化、服务、销毁四个阶段。在源码中,你可以看到如何通过实现`javax.servlet.http.HttpServlet`接口,并覆盖`doGet`或`doPost`方法来处理HTTP请求。 2. **JSP(JavaServer Pages)**:...

    Servlet源码

    Servlet源码的分析能帮助我们深入理解HTTP请求处理流程、服务器生命周期管理以及Java Web开发的底层机制。Apache Tomcat是一款广泛应用的Servlet容器,它实现了Java Servlet和JavaServer Pages(JSP)规范。在这里,...

    Spring+Servlet读取数据库返回JSON数据(源码).zip

    Spring通过IoC(Inversion of Control,控制反转)容器管理对象的生命周期和依赖关系,这使得代码更加松耦合,易于测试和维护。此外,Spring MVC是Spring框架的一部分,它为Web应用提供了一种组织代码的方式,允许...

    servlet官方源码

    `GenericServlet`是抽象类,实现了`Servlet`和`ServletConfig`接口,提供了通用的生命周期方法。`HttpServlet`继承自`GenericServlet`,专门为HTTP协议定制,提供了`doGet()`、`doPost()`等方法。 4. **请求处理**...

    eclipse+ssm框架项目源码

    在本项目中,Spring作为核心容器,管理着应用对象的生命周期和依赖注入(DI)。它还包含了SpringMVC,这是一个用于处理HTTP请求和响应的Web MVC框架。 2. **SpringMVC框架**:SpringMVC是Spring框架的一部分,负责...

    韩顺平Servlet和JSP用户管理源码

    通过学习源码,初学者可以理解Servlet生命周期、服务方法、请求和响应对象的使用等。 2. **JSP(JavaServer Pages)**:JSP是一种动态网页技术,它允许在HTML页面中嵌入Java代码。在用户管理项目中,JSP用于创建...

    入门级完整项目全程实录源码两套-Jsp&Servlet

    Servlet生命周期包括加载、初始化、服务、销毁四个阶段,而doGet和doPost方法是处理HTTP请求的主要方法。理解Servlet原理和使用是Web开发的基础。 3. **JSP与Servlet协同工作**: 在实际项目中,JSP通常用于视图...

    基于Java web的学生信息管理系统jsp+servlet(源码+数据库).zip

    Servlet的生命周期包括加载、初始化、服务和销毁四个阶段,其中初始化阶段往往用于建立数据库连接等资源。 接下来,我们关注**数据库**部分。这个系统提供了数据库文件,很可能是一个`.sql`文件,用于创建学生信息...

    servlet和struts2笔记

    通过理解其生命周期、配置以及相关的对象如 `ServletConfig` 和 `ServletContext`,开发者可以更好地构建灵活、可扩展的 Web 应用程序。此外,掌握 Servlet 的路径配置和线程安全问题是确保应用程序稳定性和性能的...

    Servlet,JSP和Spring MVC 初学指南源码

    Servlet生命周期包括加载、初始化、服务、销毁等阶段,可以通过重写`service()`方法处理HTTP请求,并通过`doGet()`或`doPost()`方法处理GET和POST请求。在实际应用中,Servlet常用于处理业务逻辑和数据操作。 JSP是...

    strus框架下学生选课系统 servlet + jsp + sqlserver

    2. **Servlet**:掌握Servlet生命周期,请求响应处理,以及与JSP的协作,例如使用HttpServlet进行请求分发和响应处理。 3. **JSP**:了解JSP的九大内置对象,EL(Expression Language)和JSTL(JavaServer Pages ...

    JavaEE Servlet JSP 源码

    通过查看和学习这些源码,开发者可以深入理解HTTP请求的处理流程、Servlet生命周期、JSP的编译过程等核心概念。 在"javaee源码"这个压缩包中,我们可以期待找到以下内容: 1. Servlet容器的核心源码:包括请求解析...

Global site tag (gtag.js) - Google Analytics