生命周期:
Servlet的生命周期可以分为四个阶段,装载类及创建实例阶段、初始化阶段、服务阶段和实例销毁阶段。
1.装载类及创建实例
客户端向Web服务器发送一个请求,请求的协议及路径必须遵守如下的格式:
http://serverip:port/application-path/resource-path
serverip为Web服务器的IP地址,也可以是域名,比如:192.168.0.1、202.196.152.115、localhost、www.sina.com.cn等。
port为Web服务器的服务端口,如果是80端口可以不写。
application-path为服务器中发布的某个应用的路径,如果为缺省应用(比如tomcat的ROOT)可以为空。
resource-path为客户端要访问的服务器中的资源的路径。如:
http://localhost:8080/serv-app/login.html 表示通过8080端口访问本地机器上名字为路径为 serv-app中/login.html对应的资源。
http://localhost:8080/serv-app/basic/time 表示通过8080端口访问本地机器上路径为serv-app的应用中/basic/time对应的资源。
本例中为tomcat服务器中webapps目录下的serv-app。/login.html和/basic/time为该应用下的资源的路径,该路径同应用路径一样为“虚拟的”路径,
由服务器把它映射为系统的具体文件或程序,具体流程如图:
servlet的部署:
<!--注册servlet-->
<servlet>
<servlet-name>DataBaseServlet</servlet-name>
<servlet-class>cn.servlet.day28.DataBaseServlet</servlet-class><!--包名加类名-->
</servlet>
<!--映射-->
<servlet-mapping>
<servlet-name>DataBaseServlet</servlet-name>
<url-pattern>/databaseservlet</url-pattern>
</servlet-mapping>
创建servlet实例:
在默认情况下Servlet实例是在第一个请求到来的时候创建,以后复用。
(有的Servlet需要复杂的操作需要载初始化时完成,比如打开文件、初始化网络连接等,可以通知服务器在启动的时候创建该Servlet的实例)
<servlet>
<servlet-name>DataBaseServlet</servlet-name>
<servlet-class>cn.servlet.day28.DataBaseServlet</servlet-class><!--包名加类名-->
<load-on-startup>1</load-on-startup>
</servlet>
注:<load-on-startup>标记的值必须为数值繻型,表示Servlet的装载顺序。
正数或零:Servlet必须在应用启动时装载,容器必须保证数值小的Servlet先装载,如果多个Servlet的<load-on-startup>取值相同,由容器决定它们的装载顺序。
负数或没有指定<load-on-startup>:由容器来决定装载的时机,通常为第一个请求到来时。
2.初始化
Servlet实例被创建,Web服务器会自动调用init(ServletConfig config)方法来初始化该Servlet。其中方法参数config中包含了Servlet的配置信息,比如初始化参数,该对象由服务器创建。
(1)配置Servlet的初始化参数:在web.xml中该Servlet的定义标记中
<servlet>
<servlet-name>DataBaseServlet</servlet-name>
<servlet-class>cn.servlet.day28.DataBaseServlet</servlet-class><!--包名加类名-->
<!--生命周期-->
<init-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://192.168.5.7:3306/db1606</param-value>
</init-param>
<init-param>
<param-name>user</param-name>
<param-value>test</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>123321</param-value>
</init-param>
</servlet>
配置了三个初始化参数url、user、password它们的值分别为jdbc:mysql://192.168.5.7:3306/db1606f和test和123321, 这样以后要修改用户名和密码不需要修改Servlet代码,只需修改配置文件即可。
(2)读取Servlet的初始化参数
ServletConfig中定义了如下的方法用来读取初始化参数的信息:
参数:初始化参数的名称。
返回:初始化参数的值,如果溡有配置,返回null。
String URL = config.getInitParameter("url");//读取Servlet的初始化参数
String USER = config.getInitParameter("user");
String PASSWORD = config.getInitParameter("password");
public java.util.Enumeration getInitParameterNames()
返回:该Servlet所配置的所有初始化参数名称的枚举。
(3)
注:init方法执行次数:在Servlet的生命周期中,init方法执行一次。
该方法执行在单线程的环境下,因此开发者不用考虑线程安全的问题。
(4)init(ServletConfig)方法与异常
a. init方法在执行过程中可以抛出ServletException来通知Web服务器Servlet实例初始化失败。
b. 一旦ServletException抛出,Web服务器不会将客户端请求交给该Servlet实例来处理,
c. 而是报告初始化失败异常信息给客户端,该Servlet实例将被从内存中销毁。
d.如果在来新的请求,Web服务器会创建新的Servlet实例,并执行新实例的初始化操作。
(5)配置初始化参数VS覆盖init(ServletConfig)方法
a.配置初始化参数与覆盖init(ServletConfig)方法并没有必然的联系。
b.配置初始化参数的目的是为了编写“通用”的Servlet,即通过改变初始化参数的值来改变Servlet的功能,而不必修改Servlet的源代码。
c.覆盖init(ServletConfig)方法的原因是某些Servlet为客户提供服务需要执行一次性的操作,比如申请资源、打开文件、建立网络连接等,这些操作要么比较耗时,要么这些资源是提供服务的必要条件。
3.服务:
Servlet实例成功创建及初始化,该Servlet实例就可以被服务器用来服务于客户端的请求并生成响应。
在服务阶段Web服务器会调用该实例的service(ServletRequestrequest, ServletResponse response)方法,request对象和response对象有服务器创建并传给Servlet实例。request对象封装了客户端发往服务器端的信息,response对象封装
了服务器发往客户端的信息。
service()方滕为Servlet的核心方法,客户端的业务逻辑应该在该方法内执行,典型的服务方法的开发流程为:
解析客户端请湂-〉执行业务逻辑-〉输出响应页面到客户端
4.销毁:
(1)当Web服务器认为Servlet实例没有存在的必要了,比如应用重新装载,或服务器关闭,以及Servlet很长时间都没有被访问过。服务器可以从内存中销毁(也叫卸载)该实例。
(2)Web服务器必须保证在卸载Servlet实例之前调用该实例的destroy()方法,以便回收Servlet申请的资源或进行其它的重要的处理。
Web服务器必须保证调用destroy()方法之前,让所有正在运行在该实例的service()方法中的线程退出或者等待这些线程一段时间。
一旦destroy()方法已经执行,Web服务器将拒绝所有的新到来的对该Servlet实例的请求,destroy()方法退出,该Servlet实例即可以被垃圾回收。
编写一个Servlet,该Servlet记录实例创建以来所有访问过该实例的客户端的IP地址到服务器的某个日志文件中。该日志文件的路径必可以在部署Servlet的时候由部署者指定。
webroot下WEB-INF下的web.xml
<?xml version="1.0" encoding="utf-8"?><!--utf-8不区分大小写-->
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!--把com.objfac.xmleditor_2.0.75插件解压到eclipse的plugins中 xml语句可变色-->
<!--在WEB-INF下只能有一个xml文件-->
<!--在WEB-INF下的classes文件因为在工程名右击properties->course->browse中选择class时隐藏-->
<!--webroot右击properties 可以复制地址-->
<!--注册servlet-->
<servlet>
<servlet-name>DataBaseServlet</servlet-name>
<servlet-class>cn.servlet.day28.DataBaseServlet</servlet-class><!--包名加类名-->
<!--生命周期-->
<init-param>
<param-name>url</param-name><!--配置Servlet的初始化参数-->
<param-value>jdbc:mysql://192.168.5.7:3306/db1606</param-value>
</init-param>
<init-param>
<param-name>user</param-name>
<param-value>test</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>123321</param-value>
</init-param>
</servlet>
<!--映射-->
<servlet-mapping>
<servlet-name>DataBaseServlet</servlet-name>
<url-pattern>/databaseservlet</url-pattern>
</servlet-mapping>
</web-app>
java代码:类继承HttpServlet
package cn.servlet.day28;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class DataBaseServlet extends HttpServlet{
private Connection connect = null;
@Override
public void init(ServletConfig config) throws ServletException {
try {
Class.forName("com.mysql.jdbc.Driver");//加载数据库驱动
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
String URL = config.getInitParameter("url");//读取Servlet的初始化参数
String USER = config.getInitParameter("user");
String PASSWORD = config.getInitParameter("password");
try {
connect = DriverManager.getConnection(URL,USER,PASSWORD);
} catch (SQLException e) {
e.printStackTrace();
}
System.out.println(connect == null?"数据库连接失败":"数据库连接成功");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String sql = "SELECT * FROM stu";
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = connect.prepareStatement(sql);
rs = ps.executeQuery();
System.out.println("姓名"+"\t"+"学号"+"\t"+"年龄"+"\t"+"年龄"+"\t"+"班级");
while(rs.next()){
String name = rs.getString("name");
String gname = rs.getString("gname");
int number = rs.getInt("number");
int age = rs.getInt("age");
int sex = rs.getInt("sex");
System.out.println(name+"\t"+number+"\t"+age+"\t"+sex+"\t"+gname);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (rs != null)
rs.close();
if (ps != null)
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
@Override
public void destroy() {
if(connect != null){
try {
connect.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}