谁能告诉我Servlet生命周期的定义和原理
解决方案 »
- Ext.tree.TreePanel的问题
- SSH两次查询同一记录…内存地址不一样…?
- 你用struts2怎么实现验证码的?
- 请教session.invalidate()引发的疑问。[为何执行后还可获取同样的session.getId()]
- struts+iBATIS??
- struts2中frameset跳转问题
- 谁能提供一些struts入门的教程!最好是视频的!谢谢!
- JBoss4 jbosscmp-jdbc.xml 对自增值的配置问题
- 高手低手赏脸帮个小忙,谢谢了
- Java如何实现函数指针?
- 求助myEclipse+struts2+hibernate+mysql做的web小系统
- ibatis 得到PreparedStatement
对于所有的来自于客户端的请求,这段程序即Servlet只需要创建一次实例,因此它节省了大量的内存。Servlet在初始化后即停驻在内存中,因此每次做出请求时无需重新加载。
具体来看看Tomcat容器即Servlet容器到底是如何管理Servlet的,它的生命周期到底是如何运行的,其中是如何与Tomcat容器实现交互,主要大家认真理解下面的分析,基本上理解Servlet生命周期也是没有问题的。 一.Tomcat 是如何加载Servlet的(Servlet的初始化) 还是以Simon 本人配置的环境举例 找到 C:\Program Files\Apache Software Foundation\Tomcat 6.0\webapps\myapp\WEB-INF下的 web.xml 这个配置文件实际上起到的最直接的作用就是管理Servlet. 在其中先加上两个 <servlet>和<serlvet-mapping>
web.xml – 继续第一次测试Servlet 的配置时的内容,复制替换即可,加的部分用红色标识
view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>My web application</display-name>
<description>
A application for test!
</description>
<servlet>
<servlet-class>ServletDemo</servlet-class>
<servlet-name>servletDemo</servlet-name>
</servlet>
<servlet>
<load-on-startup>0</load-on-startup>
<init-param>
<param-name>initial</param-name>
<param-value>10000</param-value>
</init-param>
<servlet-name>servletTest</servlet-name>
<servlet-class>MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servletTest</servlet-name>
<url-pattern>/servletpage</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>servletDemo</servlet-name>
<url-pattern>/t238servlet</url-pattern>
</servlet-mapping>
</web-app>
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <display-name>My web application</display-name> <description> A application for test! </description> <servlet> <servlet-class>ServletDemo</servlet-class> <servlet-name>servletDemo</servlet-name> </servlet> <servlet> <load-on-startup>0</load-on-startup> <init-param> <param-name>initial</param-name> <param-value>10000</param-value> </init-param> <servlet-name>servletTest</servlet-name> <servlet-class>MyServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>servletTest</servlet-name> <url-pattern>/servletpage</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>servletDemo</servlet-name> <url-pattern>/t238servlet</url-pattern> </servlet-mapping> </web-app>
新添的一个Servlet ServletDemo.java 也应该先编译好,然后放到 C:\Program Files\Apache Software Foundation\Tomcat 6.0\webapps\myapp\WEB-INF\classes目录下,此时这个目录应该有ServletDemo.class 和 MyServlet.class 两个类文件。
ServletDemo.java
view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
/**
*@author : Simon lv
演示Servlet的生命周期
继承HttpServlet
ServletDemo
*/
public class ServletDemo
extends HttpServlet {
//定义好将回发客户端页面的MIME类型,HTML格式的网页
private static final String CONTENT_TYPE = "text/html; charset=GBK";
//计数器
int count;
/**
* init 初始化方法第一次加载只会初始化一次一旦调用即说明了已经创建了ServeltDemo的实例,此后这个实例
* /将一直停留在Tomcat分配的一块内存中,下次有客户端的请求,就不用重复的实例化
* ServletConfig config 参数用来传递Servlet 在web.xml中的配置信息自动封装信息
*/
public void init(ServletConfig config) throws ServletException {
super.init(config);
//得到配置信息中initial参数的值
String initial = config.getInitParameter("initial");
try{
//转化为数字即计数器
count = Integer.parseInt(initial);
}catch(NumberFormatException e){
count =0;
}
//输出初始化信息
System.out.println("ServletDemo中的记数器Servlet 已经初始化成功!");
}
/**
* doGet 处理
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
response.setContentType(CONTENT_TYPE);
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head><title>LifeServletDemo</title></head>");
out.println("<body bgcolor=\"#ffffff\">");
count++;
out.println("自从加载后(读取参数化后)");
out.println("ServletDemo 已经被访问过了");
out.println(count+" 次");
out.println("</body>");
out.println("</html>");
out.close();
System.out.println("ServletDemo中的的doGet 方法被执行一次");
}
//doPost()方法
public void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
doGet(request, response);
}
//清除资源
public void destroy() {
System.out.println("ServletDemo 实例资源已经释放!");
}
}
import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.*; /** *@author : Simon lv 演示Servlet的生命周期 继承HttpServlet ServletDemo */ public class ServletDemo extends HttpServlet { //定义好将回发客户端页面的MIME类型,HTML格式的网页 private static final String CONTENT_TYPE = "text/html; charset=GBK"; //计数器 int count; /** * init 初始化方法第一次加载只会初始化一次一旦调用即说明了已经创建了ServeltDemo的实例,此后这个实例 * /将一直停留在Tomcat分配的一块内存中,下次有客户端的请求,就不用重复的实例化 * ServletConfig config 参数用来传递Servlet 在web.xml中的配置信息自动封装信息 */ public void init(ServletConfig config) throws ServletException { super.init(config); //得到配置信息中initial参数的值 String initial = config.getInitParameter("initial"); try{ //转化为数字即计数器 count = Integer.parseInt(initial); }catch(NumberFormatException e){ count =0; } //输出初始化信息 System.out.println("ServletDemo中的记数器Servlet 已经初始化成功!"); } /** * doGet 处理 */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType(CONTENT_TYPE); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head><title>LifeServletDemo</title></head>"); out.println("<body bgcolor=\"#ffffff\">"); count++; out.println("自从加载后(读取参数化后)"); out.println("ServletDemo 已经被访问过了"); out.println(count+" 次"); out.println("</body>"); out.println("</html>"); out.close(); System.out.println("ServletDemo中的的doGet 方法被执行一次"); } //doPost()方法 public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } //清除资源 public void destroy() { System.out.println("ServletDemo 实例资源已经释放!"); } }
这句话的输出即证明了 在MyServlet中的 init方法被调用了一次! MyServlet.java中的相关代码:
view plaincopy to clipboardprint?
//初始化方法第一次加载只会初始化一次
public void init(ServletConfig config) throws ServletException {
super.init(config);
String initial = config.getInitParameter("initial");
try{
count = Integer.parseInt(initial);
}catch(NumberFormatException e){
count =0;
}
System.out.println("MyServlet 中的记数器Servlet 已经初始化成功!");
}
//初始化方法第一次加载只会初始化一次 public void init(ServletConfig config) throws ServletException { super.init(config); String initial = config.getInitParameter("initial"); try{ count = Integer.parseInt(initial); }catch(NumberFormatException e){ count =0; } System.out.println("MyServlet 中的记数器Servlet 已经初始化成功!"); }
但是我在MyServlet.java 和上面新加的ServletDemo.java中都存在 init()方法,但是为什么仅仅MyServlet.java中的方法被调用了呢?原因就在于在 web.xml中,指定了Tomcat一启动就初始化的实例
view plaincopy to clipboardprint?
<servlet>
<load-on-startup>0</load-on-startup>
<init-param>
<param-name>initial</param-name>
<param-value>10000</param-value>
</init-param>
<servlet-name>servletTest</servlet-name>
<servlet-class>MyServlet</servlet-class>
</servlet>
<servlet> <load-on-startup>0</load-on-startup> <init-param> <param-name>initial</param-name> <param-value>10000</param-value> </init-param> <servlet-name>servletTest</servlet-name> <servlet-class>MyServlet</servlet-class> </servlet>
这样就通知了Tomcat在它的服务一启动的时候,就要去加载所对应的Servlet-class MyServlet这个类,0代表级别,随后是1.2.3.4---- 0最高。Tomcat首先把这些类加载并实例化,保存在自己的Servlet容器池中,如果以后有请求,就直接从容器池中取出来,处理相应的请求。 要注意的是:此时并没有来自于客户端的请求,是先于客户请求直接就已经加载完毕了的。
下面我们去请求 ServletDemo ,它没有像MyServlet 那样在客户端请求前就被Tomcat实例化了的,它需要由请求完成实例化。 在IE浏览器中输入 :http://localhost:8080/myapp/t238servlet 在页面上看到 图片2见附件
在Tomcat 控制台上看到: 注意红线部分! 图片2见附件 说明了什么? 说明了,Tomcat加载Servlet实例至少有两种方法,一种是通过在 web.xml配置文件中设置加载级别,另一种是通过客户端访问到某个具体的Servlet时,也一定会完成初始化,加载这个实例!一旦实例被加载,后面的请求,将不会再重新实例化Servlet。 再刷新页面:http://localhost:8080/myapp/t238servlet
对应的网页 和Tomcat 图片3见附件 ServletDemo中的doGet方法被执行一次 多输出了一句,但是 初始化的信息没有再输出,说明了 init()方法只执行了一次,也即说明了Servlet实例只被Tomcat 加载了一次!
换个页面请求一次 http://localhost:8080/myapp/servletpage相应页面和Tomcat控制台为: 图片4见附件 MyServlet 的doGet()方法被执行了一次。 Init()方法呢? 答案是 MyServlet 在客户端请求之前就已经被Tomcat加载,还记得这段代码吗?
view plaincopy to clipboardprint?
<servlet>
<load-on-startup>0</load-on-startup>
<init-param>
<param-name>initial</param-name>
<param-value>10000</param-value>
</init-param>
<servlet-name>servletTest</servlet-name>
<servlet-class>MyServlet</servlet-class>
</servlet>
<servlet> <load-on-startup>0</load-on-startup> <init-param> <param-name>initial</param-name> <param-value>10000</param-value> </init-param> <servlet-name>servletTest</servlet-name> <servlet-class>MyServlet</servlet-class> </servlet>
目前只能知道是这么种情况,但是为什么输入不同的URL就能访问到不同的Servlet,服务器端如何判断来自客户端的请求要做什么,要交给那个 JAVA程序去处理呢?并且 ServletDemo 即第一个页面是访问了1次,但是MyServlet的页面为10001次,这些都是从哪里得到的? 继续….. 打开 web.xml 配置文件 选两段内容
+ expand sourceview plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
<servlet-mapping>
<servlet-name>servletDemo</servlet-name>
<url-pattern>/t238servlet</url-pattern>
</servlet-mapping>
<servlet-mapping> <servlet-name>servletDemo</servlet-name> <url-pattern>/t238servlet</url-pattern> </servlet-mapping>
因为我们部署在Tomcat上的JSP环境是 myapp 所以我们在访问服务器时,myapp是要写上的,就相当于一个根目录。 http://localhost:8080/myapp/t238servlet 这是一个请求的网址。 当客户端提交这个请求时,服务器会对这个网址进行分析,首先会通过 myapp 定位到相应的根目录,再通过 /t238servlet 确定要访问的资源。 在配置文件中
+ expand sourceview plaincopy to clipboardprint?
<servlet-name>servletDemo</servlet-name>
<url-pattern>/t238servlet</url-pattern>
<servlet-name>servletDemo</servlet-name> <url-pattern>/t238servlet</url-pattern>
服务器端就已经明确的告诉了程序 需要用一个名叫 servletDemo 的程序去处理这个请求。 于是….. servlet-name 就可以定位到真正的可以处理客户端请求的类 ServletDemo.class
view plaincopy to clipboardprint?
<servlet>
<servlet-class>ServletDemo</servlet-class>
<servlet-name>servletDemo</servlet-name>
</servlet>
<servlet> <servlet-class>ServletDemo</servlet-class> <servlet-name>servletDemo</servlet-name> </servlet>
ServletDemo.class 在哪里? 就位于我们部署好的路径中 \webapps\myapp\WEB-INF\classes 注意,真正的处理程序是 ServletDemo.class 不同的请求,服务器通过 url-pattern 的设置,就能将请求交给相应的服务器端Servlet程序去处理,因此看到的效果就不一样,Tomcat控制台中显示的效果也就不一样。
第二个问题? 第一个页面显示的是访问1次,而后一个页面是10001次。原因在于 web.xml 配置文件中
view plaincopy to clipboardprint?
<servlet>
<load-on-startup>0</load-on-startup>
<init-param>
<param-name>initial</param-name>
<param-value>10000</param-value>
</init-param>
<servlet-name>servletTest</servlet-name>
<servlet-class>MyServlet</servlet-class>
</servlet>
<servlet> <load-on-startup>0</load-on-startup> <init-param> <param-name>initial</param-name> <param-value>10000</param-value> </init-param> <servlet-name>servletTest</servlet-name> <servlet-class>MyServlet</servlet-class> </servlet>
即MyServlet配置信息中有一个参数为 initial ,值为 10000 MyServlet中的初始化方法
+ expand sourceview plaincopy to clipboardprint?
//初始化方法第一次加载只会初始化一次
public void init(ServletConfig config) throws ServletException {
super.init(config);
String initial = config.getInitParameter("initial");
try{
count = Integer.parseInt(initial);
}catch(NumberFormatException e){
count =0;
}
System.out.println("MyServlet 中的记数器Servlet 已经初始化成功!");
}
//初始化方法第一次加载只会初始化一次 public void init(ServletConfig config) throws ServletException { super.init(config); String initial = config.getInitParameter("initial"); try{ count = Integer.parseInt(initial); }catch(NumberFormatException e){ count =0; } System.out.println("MyServlet 中的记数器Servlet 已经初始化成功!"); }
页面输出部分: out.println("自从加载后(读取参数化后)"); out.println("MyServlet 中的 已经被访问过了"); out.println(count+" 次");
相信看完这些就能基本上明白这种差异了,并且发现由于
+ expand sourceview plaincopy to clipboardprint?
<servlet>
<servlet-class>ServletDemo</servlet-class>
<servlet-name>servletDemo</servlet-name>
</servlet>
<servlet> <servlet-class>ServletDemo</servlet-class> <servlet-name>servletDemo</servlet-name> </servlet>
没有这种初始化参数,自然就无法获得这种效果了。
但是随即在 以上代码中填入
view plaincopy to clipboardprint?
<init-param>
<param-name>initial</param-name>
<param-value>100</param-value>
</init-param>
<init-param> <param-name>initial</param-name> <param-value>100</param-value> </init-param>
Ctrl+S 保存 web.xml 再次刷新 http://localhost:8080/myapp/t238servlet马上就能看到
图片5见附件
从100次开始了!!!
由于 web.xml 就是Tomcat管理Servlet的环境,Tomcat不需要关闭,只要 web.xml做出改动,它的能够识别到这种改动。 所以在上面就能够清楚的看到 : ServletDemo实例资源已经释放,MyServlet 也是如此,即都调用了它们的 //清除资源
public void destroy() {
System.out.println("MyServlet 实例资源已经被释放!"); }
方法。 并且重新初始化并加载 优先级别为0的 MyServlet,同时因为重新刷新了http://localhost:8080/myapp/t238servlet 由 ServletDemo处理这个请求,自然ServletDemo先实例化,并被加载,同时因为重新制定了初始化参数,所以效果自然也变成 101次访问!
服务
毁灭
加载和实例化 - 初始化 - 服务 - 销毁
ini() 初始化时调用的方法
destroy() 销毁Servlet实例之前调用的方法
第一次使用Servlet时 加载和实例化 - 初始化 - 服务
第二次和第N次使用时只 服务
服务器关闭时或Servlet类发生变化就会销毁(destroy())
注意:Servlet只有一个对象,如果同时多用户请求时以多线程的方式处理请求。
三个方法,第一次调用时用init() 然后调用service(),最后销毁.
init()
serivice()
destory()
实例化-->Servlet容器创建Servlet的实例
初始化-->该容器调用init()方法
服务---->如果请求Servlet,则容器调用service()方法
销毁---->销毁实例之前调用destory()方法
不可用-->销毁实例并标记为垃圾收集
cookie.setMaxAge(3*60); //以“分钟”为单位
response.addCookie(cookie);
重启或关闭服务器他就死了,
真直白...