以下是我自学servlet生命周期的感悟:
-
Servlet定义:
- 宏观地讲,servlet是连接web服务器与Java程序的协议,是一种通信规范。这个规范是以一套接口的形式体现的。它连接的是web服务器和web端的Java代码(这点一定要深刻理解)。
- 通常来说,Servlet是宏观上Servlet规范中的一个具体的接口。Servlet规范中包含一套接口。而Servlet接口仅仅是其中之一。这个接口存在于javax.Servlet这个包下 ,.
- 微观地讲,Servlet是Servlet接口实现类的一个实例对象,是运行在服务器上的一段java小程序,即Server Applet,也就是Servlet这个单词的来历。Servlet的主要功能是根据客户端提交的请求,调用服务器端相关的java代码,完成对请求的处理与运算。也就是Servlet这个接口的实现类在服务器上运行,根据请求去调用相关的代码。
-
Servlet生命周期:
- 实例化(Servlet对象的创建)-----初始化(Servlet对象的初始化)-----服务(Servlet对象服务的执行)-----销毁(Servlet对象被销毁)
- Servlet的整个生命周期的执行,均由web服务器负责管理。
- 当请求到达服务器,服务器会对请求(URL)进行解析,解析出来URI,将请求和Servlet映射,如果Servlet被实例化,则直接执行service()方法,然后执行destroy()方法,若servlet没有实例化,则执行无参构造器,再执行init()这个方法,再执行service()方法,最后执行destroy()方法。
- 举例说明Servlet生命周期:
- 先创建个web项目,然后再src下建立一个类,实现javax.servlet下的Servlet接口,实现类代码如下:
package com.bjpowernode.servlets;
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class SomeServlet implements Servlet {
public SomeServlet() {
System.out.println("创建SonmeServlet实例");
}
@Override
public void destroy() {
System.out.println("销毁SonmeServlet实例");
}
@Override
public ServletConfig getServletConfig() {
System.out.println("执行getServletConfig()");
return null;
}
@Override
public String getServletInfo() {
System.out.println("执行getServletInfo()");
return null;
}
@Override
public void init(ServletConfig arg0) throws ServletException {
System.out.println("初始化SonmeServlet实例");
}
@Override
public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException {
System.out.println("执行SonmeServlet实例的service()方法");
}
}
- 接着在WEB-INF下的web.xml文件中写servlet和url映射关系的注册,分成两部分,两部分缺一不可。刚开始写第二段注册,就是map那段,运行server服务器一直启动不了,整整搞了一上午,我把服务器关了重开,remove然后重新add,还删除了项目又重建,最终发先了问题所在,对于url-pattern而言,这样的命名方式是不允许的,同样取名包名+类名(/myservlet/Signup)这样的格式也是不可以的,因为这样会引起混淆。所以我们把url-pattern里的路径改成/servlet/Signup就可以了,这个名字可以随便取。终于启动了,可以访问了,代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
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">
<!-- 注册Servlet -->
<servlet>
<servlet-name>some-servlet</servlet-name>
<servlet-class>com.bjpowernode.servlets.SomeServlet</servlet-class>
</servlet> <!-- 对servlet类的注册 -->
<servlet-mapping>
<servlet-name>some-servlet</servlet-name>
<url-pattern>/servlet/some</url-pattern>
<!-- 对于url-pattern而言,这样的命名方式是不允许的,同样取名包名+类名(/myservlet/Signup)这样的格式也是不可以的,因为这样会引起混淆。所以我们把url-pattern里的路径改成/servlet/Signup就可以了,这个名字可以随便取。 -->
</servlet-mapping><!-- servlet和url映射关系的注册,两部分缺一不可 -->
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
-
Servlet特征:
- Servlet是单例多线程的(也就是只能创建一次实例对象,初始化一次,而且可以多个浏览器去访问,支持多线程)
- 一个Servlet实例只会执行一次无参构造器与init()方法,并且是在第一次访问时执行(可以是刷新)。
- 用户每提交一次对当前Servlet的请求,就会执行一次service方法
- 一个servlet实例只会执行一次destroy方法,在应用停止时执行。
- 由于Servlet是单例多线程的,所以为了保证其线程安全性,一般情况下是不为Servlet类定义可修改的成员变量的。因为每个线程均可修改这个成员变量,会出现线程安全问题,除非它是不可修改的比如光有get没有set。
- 默认情况下,Servlet在Web容器启动时是不会被实例化的