android开发 Tomcat服务器之Servlet生命周期

Servlet是一种可以在Servlet容器中运行的组件,那么理所当然就应该有一个从创建到销毁的过程,这个过程我们可以称之为Servlet生命周 期。Servlet的生命周期可以分为加载、实例化、初始化、处理客户请求和卸载五个阶段,体现在方法上主要是init()、service()和 destroy()三个方法。生命周期的具体说明如下: 

Servlet容器完成加载Servlet类和实例化一个Servlet对象 
init()方法完成初始化工作,该方法由Servlet容器调用完成 
service()方法处理客户端请求,并返回响应结果 
destroy()方法在Servlet容器卸载Servlet之前被调用,释放一些资源 
加载并初始化Servlet 
在前面已经说过Servlet容器完成加载和实例化Servlet的工作,该工作既可以在容器启动时完成,也可以在容器收到请求时完成,或者是两 者之间的某个时间启动。之后需要初始化Servlet,即读取配置信息、读取初始化参数等,这些基本上在整个生命周期中只需要执行一次。关于init() 方法已经在积累GenericServlet中提供缺省实现,如果不需特殊处理则没有必要再进行定义,否则要重写。 
处理客户端请求 
当容器接收到客户端请求时,Servlet引擎将创建一个ServletRequest请求对象和一个ServletResponse响应对象,然后把这两个对象作为参数传递给对应Servlet对象的service方法。 
该方法是一个重点实现的方法,ServletRequest对象可以获得客户端发出请求的相关信息,如请求参数等,ServletResponse对象可以使得Servlet建立响应头和状态代码,并可以写入响应内容返回给客户端。 
在此说明一点,当Servlet中有doGet()或者doPost()方法时,那么service方法就可以省略,默认为调用这两个方法。 
卸载Servlet 
Servlet的卸载是由容器本身定义和实现,在卸载Servlet之前需要调用destroy()方法,以让Servlet自行释放占用的系统 资源。虽然Java虚拟机提供了垃圾自动回收处理机制,但是有一部分资源却是该机制不能处理或延迟很久才能处理的,如关闭文件,释放数据库连接等。 
Servlet生命周期的五个阶段是相互关联的,后面几个阶段建立在前面阶段的基础之上,在使用Servlet的时候可以根据自己的需要灵活处理。

一、Servlet简介 :
Servlet:即为Servlet(服务器)+Let(小的)即为服务器端小程序。

二、Servlet作用:
开发网站 。它是一个Java程序,动态生成HTML网页。

***Request-Response模型 :
1、客户端先发生请求,服务器端产生响应。
2、请求和响应成对出现,一次请求对应一次响应。
Servlet是基于请求-响应模型的。

三、程序员开发Servlet做的事情 :

必须实现SUN公司提供的Servlet接口(Servlet接口来自JavaEE API)编写class实现Servlet接口,在web工程中web.xml 配置文件中对Servlet进行注册。

四、Servlet 快速入门 案例
1、创建web project
2、创建demo1.html默认 Visual HTML Designer 开发慢 ---- 将HTML 默认编辑器改为:MyEclipse HTML Editor
window -- preferences -- general -- Editors -- File Associations --*.html--下边的HTML Editor设为default
3、编写一个Servlet生成一个HTML页面 创建一个class 继承 HttpServlet。
代码如下 :
------
public class ServletDemo extends HttpServlet{
 @Override
 //处理GET请求
 protected void doGet(HttpServletRequest req, HttpServletResponse resp)
   throws ServletException, IOException {
  // TODO Auto-generated method stub
//  super.doGet(req, resp);
  System.out.println("helloWorld!");
  // 通过Servlet动态生成HTML 通过响应对象 获得输出流

  // 获得输出流之前,设置响应输出编码集
  resp.setContentType("text/html;charset=utf-8");
  PrintWriter out=resp.getWriter();
  // 生成是HTML源代码
  out.println("<html>");
  out.println("<body>");
  for(int i=0;i<3;i++){
   out.println("<h1>这是一个用Servlet生成的网页!</h1>");
  }
  out.println("</body>");
  out.println("</html>");  
 }
 @Override
 //处理POST请求
 protected void doPost(HttpServletRequest req, HttpServletResponse resp)
   throws ServletException, IOException {
  // TODO Auto-generated method stub
 }
}
------

4、编写的Servlet程序 需要在web.xml 中进行注册 ---为Servlet 配置虚拟访问路径 ,客户端通过路径访问该Servlet /hello
代码如下 :
------
<servlet>
 <servlet-name>Hello</servlet-name>
 <servlet-class>cn.android.servlet.ServletDemo</servlet-class> 
</servlet>

<servlet-mapping>
 <servlet-name>Hello</servlet-name>
 <url-pattern>/hello</url-pattern>
</servlet-mapping>

(注:配置Servlet的最终目的是:用虚拟路径/hello访问类cn.android.servlet.ServletDemo。
------
5、覆盖doGet 和 doPost 
代码见以上第3点

使用Servlet 动态Servlet 生成HTML

总结 :编写Servlet的3个步骤是:
1)继承javax.servlet.http.HttpServlet
2)在web.xml中配置虚拟路径
3)覆盖doGet doPost
---

五、客户端访问服务器动态web 资源 ---- 通过虚拟路径 映射找到要执行Servlet 程序
客户端请求方式 ---- 会决定去执行 doGet 或者 doPost

Servlet没有main函数,不是独自运行,需要运行在tomcat服务器上,由tomcat程序调用Servlet执行

开发JavaSE程序 导包 import ---- import java.io.Reader;  import java.util.ArrayList;  位于JRE/rt.jar中
开发JavaEE程序 导包 import javax.servlet.http.HttpServlet;  MyEclipse提供javaee.jar  Tomcat提供 lib/servlet-api.jar

六、实验:手动编译运行一个Servlet(练习 )

1、在webapps 创建 mytest目录(网站根目录)
2、在mytest下新建WEB-INF目录,在目录下新建 web.xml 
3、Serlvet类编写在哪个目录(classes)
* src中编写Servlet 运行到tomcat 时,类class文件 复制WEB-INF/classes目录  复制Demo1Servlet.java源码到classes
4、对.java文件进行编译 需要tomcat提供 servlet-api.jar 
javac -classpath E:\apache-tomcat-6.0.14\lib\servlet-api.jar -d . ServletDemo.java
即:javac -classpath jar包的路径 -d . ServletDemo.java
cn.itcast.servlet.Demo1Servlet 类编译class后  ---- classes/cn/itcast/servlet/Demo1Servlet.class

sun 规定Servlet程序必须实现Servlet接口
Servlet接口有实现类GenericServlet, GenericServlet子类 HttpServlet , 编写Servlet程序只需要继承HttpServlet 间接实现Servlet接口 (简化开发)

Servlet接口和GenericServlet类中 并没有与协议相关API (只定义了通用API),HttpServlet 提供了很多与HTTP协议相关API

Servlet接口中提供5个方法,其中init service destroy 这三个方法描述了Servlet 对象生命周期(Servlet对象从创建到销毁完整过程)

第一次访问Servlet 时,Servlet构造方法执行、init 执行,执行service
如果不是第一次访问Servlet ,直接执行service 
正常关闭服务器 destroy 执行 --- 执行tomcat shutdown.bat

结论:
1、Servlet对象只会在服务器端创建一个,init 方法也只会执行一次 , 默认是在第一次访问Servlet时 创建对象 调用init
2、每一次客户端HTTP请求,都将执行服务器Servlet对象 service方法 (以独立线程进行执行)
* 不出现并发问题,Servlet对象只有一个实例,通常不编写Servlet对象成员变量
* 栈空间是线程私有的 不会发生并发问题 ,只有堆空间是进程独享,进程由多个线程组成,堆空间上变量才能导致 多线程并发问题
3、在服务器正常关闭时,执行一次 destroy

之前快速入门案例 继承HttpServlet 覆盖doGet doPost 没有编写service ------ service 和 doGet/doPost 关系
* 在HttpServlet中 service方法内 根据请求方式执行 doGet 或者 doPost  (查看Servlet源代码 )
--- 导入源码

默认Servlet程序是在第一次访问时,创建对象,执行init ----- 如果想在服务器启动时 创建Servlet对象 执行init 有无办法???
* 在<Servlet> 元素中 添加<load-on-startup> 语法 <load-on-startup>数字(加载Servlet优先级 0-9 0优先级最高 )</load-on-startup>
应用: Struts1 ActionServlet 核心控制器 在服务器启动时 加载配置文件

编写Servlet注意事项
1、Servlet初始化时覆盖init() ,无需覆盖init(config)
* 覆盖无参数init 也会得到初始化执行,因为在GenericServlet中 init(config) 调用 init() 
思考题
class A extends HttpServlet {
   public void init(){
      sysout(1);
   }
   public void init(ServletConfig) { 
      sysout(2); 
   }
}
初始化时 执行哪个方法 ?答案:2 只会执行生命周期 init(config)

2、继承HttpServlet 只需覆盖doGet 和 doPost 无需覆盖service

3、当doGet 和 doPost 代码完全相同 互相调用 简化编程

 

-------
七、虚拟路径映射三种书写格式 :
1、完全路径匹配:以/开始 ,不存在通配符*。例如:/demo1、/demo2、/aa/index.html 
2、目录匹配:以/开始,使用通配符 *。   例如: /*   /aa/*   /bb/cc/*
(注:*指某个目录下的所有资源)
3、扩展名匹配:不能以/开始,使用通配符。*.do 、*.action ----- /*.do、/aa/*.action 错误的

*** 假如有一天访问 html 都报404 时候,确认路径真的没写错 ----- 服务器启动时 没有正确加载工程
优先顺序:完全路径> 目录 > 扩展名

八、案例 乘法表 ---- 打印乘法表 
需求:编写html页面在页面中提供form表单,要求用户输入一个数字
服务器Demo4Servlet 根据用户输入数字打印 几乘几 乘法表

路径写法:相对路径 、绝对路径
相对路径 例如: hello ./hello ../hello
* hello 当前目标hello资源 与 ./hello 意义相同
* ../hello 代表上一级目录hello 

九、例1 :http://localhost/day5/demo4/chengfabiao.html  ----- 目标:http://localhost/day5/demo4 答案 ../demo4
http://localhost/day5/demo4/chengfabiao.html --- 链接 ./hello  结果 http://localhost/day5/demo4/hello
http://localhost/day5/demo4/chengfabiao.html --- 链接 ../hello  结果http://localhost/day5/hello 
* 如果使用相对路径,分析当前路径 与 目标路径  根据相对位置编写路径

绝对路径 例如: /hello 、/day5/hello、http://localhost/day5/hello 
分析/ 含义
客户端访问服务器 http://localhost ---- 访问tomcat主页
http://localhost/day5 ---- 访问day5工程主页
http://localhost/day5/demo4 --- 访问乘法表Servlet
* 绝对路径不用考虑当前文件url ,从服务器根目录 / 找到目标路径 就可以了

目标:http://localhost/day5/demo4 ---- 绝对 /day5/demo4

服务器端和客户端对于/ 的区别
客户端访问 在tomcat服务器之外,找day5工程下 demo4 资源 ---- /day5/demo4
服务器内部路径 在day5工程内 /demo4  ---- /当前工程

结论:
1、都用绝对路径
2、客户端与服务器 / 写法不同
客户端 /工程名/资源 ---- 在服务器外部
服务器内部 /资源 --- 不需要写/工程名

 
--------------------------------------下午---------------------------------------
十、Servlet生命周期 
Servlet 生命周期 init(ServletConfig) service(ServletRequest,ServletResponse) destroy()

配置web.xml 通过<init-param> 为Servlet对象提供初始化参数,都可以通过init方法中ServletConfig对象获得
* 在<Servlet> 标签中 
* ServletConfig 只是接口,实现类由Tomcat服务器提供

ServletConfig 通过下面方法获得初始化参数
String getInitParameter(String name)  获得指定参数值,传入参数name
Enumeration getInitParameterNames()  获得所有参数name的集合
* Enumeration 接口 就是 Iterator前身 Enumeration 线程安全的  Iterator 线程不安全

ArrayList 替代 Vector 、HashMap 替代 HashTable 、StringBuilder 替代 StringBuffer 
* 线程不考虑安全问题的这些类 效率更高

注意事项:ServletConfig 实例 针对每一个Servlet实例 提供初始化参数,一个Servlet对象应该有一个对应ServletConfig实例
ServletConfig只能获得 当前Servlet实例初始化信息

结论:在编写Servlet时,无需覆盖init(ServletConfig) 在Servlet类中只需通过getServletConfig() 方法 获得config对象
* 覆盖有参数init 没有执行 this.config= config ---- 结果 getServletConfig 返回 null


十一、ServletContext  每个工程对应一个独立ServletContext对象 ,全局Servlet控制对象
1、获得ServletContext 需要通过ServletConfig接口 方法 
2、因为ServletContext 是每个工程只有一个,实现数据共享
ServletContext 应用
1、获得整个web工程全局(该工程所有Servlet都可以访问)初始化参数 
2、实现数据共享,ServletContext对象是全局唯一,保存到该对象数据,可以从当前应用任何程序获得
3、利用ServletContext对象读取web应用中资源文件

第一个应用:配置全局初始化参数
ServletContext 与 ServletConfig 提供初始化参数不同 ??
配置ServletContext全局参数 <context-param>

getServletContext().getInitParameter(参数名称);

第二个应用:使用ServletContext对象实现全局数据共享
如果在ServletContext中保存一个数据,所有Servlet都可以访问该数据
网站访问计数案例

向ServletContext保存数据 setAttribute() ------- 相当于map.put
取得ServletContext中数据 getAttribute ---- map.get 这里取出数据是 Object 需要强制类型转换

第三个应用:通过ServletContext读取web 工程中资源文件
回顾 java工程读取文件 通过main函数读取 ---- JVM中直接运行
web 工程读文件 通过Servlet读取  ----- Tomcat中运行

十二、创建四个文件 
1.txt ---- 工程根目录
2.txt ---- WebRoot目录
3.txt ---- WEB-INF目录
4.txt ---- src目录

!!!!!!!!在web 工程读取文件必须使用绝对磁盘路径 D:\work\myclipse\work20120713\day5\1.txt
1.txt在工程根目录,不在WebRoot 中 --- 只有WebRoot 会被发布 ---- 1.txt 不存在无法读取
4.txt 在src目录 --- src中所有java文件编译.class 保存WEB-INF/classes  --- src中所有配置文件 
会自动复制WEB-INF/classes --- 可以读取

file = getServletContext().getRealPath("/2.txt"); ---- 将网站根目录下2.txt 文件路径 转换为绝对磁盘路径
file = getServletContext().getRealPath("/WEB-INF/3.txt"); ---- 将网站根目录下WEB-INF目录下 3.txt 转换绝对磁盘路径
file = getServletContext().getRealPath("/WEB-INF/classes/4.txt"); ---- 获得网站根目录下WEB-INF下classes 下4.txt 绝对磁盘路径

如果读取文件 在WEB-INF/classes下 
file = Demo9Servlet.class.getResource("/4.txt").getFile(); // 这里 / 代表classpath根目录


十三、缺省Servlet:
1、配置url-pattern 为 /
2、所有静态WEB资源 html,都由缺省的Servlet返回给客户端。

在tomcat中已经配置缺省Servlet : org.apache.catalina.servlets.DefaultServlet的Servlet
conf/web.xml 
* 位于tomcat/conf/web.xml 当前配置将对整个服务器内部所有网站 有效
缺省Servlet
1、获得客户端要访问哪个web资源
2、判断服务器端该web资源是否存在
3、如果资源存在,读取资源内容返回客户端
4、如果资源不存在 ,返回404
-------------------------------

十四、文件复制掌握三个:
1、一个字节一个字节读
InputStream in ...
OutputStream out ...
int b;
while((b=in.read)!=-1){
   out.write(b);
}
2、一行一行读
BufferedReader reader ...
PrintWriter out ...
String line;
while((line = reader.readLine())!=null){
   out.println(line);
}

3、使用数组缓冲读
InputStream in ...
OutputStream out ...
byte[] buf = new byte[8192];
int len;
while((len = in.read(buf))!=-1){
   out.write(buf,0,len);
}


今日复习内容:
1、Servlet的HelloWorld !  ---- 整理Servlet开发步骤
1)继承javax.servlet.http.HttpServlet
2)在web.xml中配置虚拟路径
3)覆盖doGet doPost

2、在MyEclipse链接Servlet源代码
选中HttpServlet点Ctrl,然后将已存在的源码文件路径选中导入即可。

3、修改Servlet模板

4、Servlet生命周期 ? init方法 service方法 destroy方法何时执行?
service 和 doGet doPost 关系
init(ServletConfig) 和 init() 关系
---
Servlet生命周期 :Servlet对象从创建到销毁完整过程。
第一次访问Servlet 时,Servlet构造方法执行、init 执行,执行service
如果不是第一次访问Servlet ,直接执行service 
正常关闭服务器 destroy 执行 --- 执行tomcat shutdown.bat
在HttpServlet中 service方法内 根据请求方式执行 doGet 或者 doPost
Servlet初始化时覆盖init() ,无需覆盖init(config)
* 覆盖无参数init 也会得到初始化执行,因为在GenericServlet中 init(config) 调用 init()
5、url配置三种方式:完全匹配、目录匹配和扩展名 匹配
1)、完全路径匹配 : 以/开始  例如:/demo1、/demo2、/aa/index.html  ----- 不存在通配符* 
2)、目录匹配 : 以/开始 使用通配符* 例如:/*、/aa/*、/bb/cc/*  ---- /a*b* /a* 错误的
* 某个目录下所有资源 
3)、扩展名匹配:不能以/开始 使用通配符 例如:*.do 、*.action ----- /*.do、/aa/*.action 错误的

6、乘法表案例

7、ServletConfig 配置初始化参数
ServletConfig 通过下面方法获得初始化参数
String getInitParameter(String name)  获得指定参数值,传入参数name
Enumeration getInitParameterNames()  获得所有参数name的集合

8、ServletContext 全局参数、访问次数案例、读取web文件 (复习读取文件)

9、缺省Servlet 案例 (复习文件复制三种写法)
缺省Servlet
1、配置url-pattern 为 /
2、所有静态web资源 html、图片 都是由 缺省Servlet返回给客户端

在tomcat中已经配置缺省Servlet : org.apache.catalina.servlets.DefaultServlet的Servlet
conf/web.xml 
* 位于tomcat/conf/web.xml 当前配置将对整个服务器内部所有网站 有效
缺省Servlet
1、获得客户端要访问哪个web资源
2、判断服务器端该web资源是否存在
3、如果资源存在,读取资源内容返回客户端
4、如果资源不存在 ,返回404

原文地址:https://www.cnblogs.com/cuixiaodong427/p/3108270.html