自定义servlet是继承的HttpServlet,HttpServlet继承自GenericServlet,GenericServlet实现的javax.servlet. 这里要注意的是,GenericServlet是一个通用的,不特定于任何协议的Servlet,它实现了Servlet接口。而HttpServlet继承于GenericServlet,因此HttpServlet也实现了Servlet接口。所以我们定义Servlet的时候只需要继承HttpServlet即可。而HttpServlet是特定于HTTP协议的类,所以HttpServlet中实现了service()方法,并将请求ServletRequest、ServletResponse 强转为HttpRequest 和 HttpResponse。
Servlet接口,此接口的主要定义方法如下:
void init(ServletConfig var1) throws ServletException;
ServletConfig getServletConfig();
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
String getServletInfo();
void destroy();
在代码中,Servlet生命周期由接口javax.servlet.Servlet定义。所有的Java Servlet 必须直接或间接地实现javax.servlet.Servlet接口,这样才能在Servlet Engine上运行。javax.servlet.Servlet接口定义了一些方法,在Servlet 的生命周期中,这些方法会在特定时间按照一定的顺序被调用。
下面是主要方法的的说明
init()方法
在Servlet的生命周期中,仅执行一次init()方法,它是在服务器装入Servlet时执行的,可以配置服务器,以在启动服务器或客户机首次访问Servlet时装入Servlet。无论有多少客户机访问Servlet,都不会重复执行init();
service()方法
它是Servlet的核心,每当一个客户请求一个HttpServlet对象,该对象的Service()方法就要调用,而且传递给这个方法一个“请求”(ServletRequest)对象和一个“响应”(ServletResponse)对象作为参数。在HttpServlet中已存在Service()方法。默认的服务功能是调用与HTTP请求的方法相应的do功能。
destroy()方法
仅执行一次,在服务器端停止且卸载Servlet时执行该方法,有点类似于C++的delete方法。一个Servlet在运行service()方法时可能会产生其他的线程,因此需要确认在调用destroy()方法时,这些线程已经终止或完成。
所以servlet生命周期分为三个阶段:
- 初始化阶段 调用init()方法
- 响应客户请求阶段 调用service()方法
- 终止阶段 调用destroy()方法
当启动Servlet容器时,容器首先查找一个配置文件web.xml,这个文件中记录了可以提供服务的Servlet。每个Servlet被指定一个Servlet名,也就是这个Servlet实际对应的Java的完整class文件名。Servlet容器会为每个自动装入选项的Servlet创建一个实例。所以,每个Servlet类必须有一个公共的无参数的构造器 servlet在servlet Engine上的运行加载顺序:
不存在的servlet实例————>容器装载servlet ————>创建servlet实例————>初始化servlet:调用servlet的init()方法————>处理业务:调用serlvet实例的service()方法————>结束servlet:调用实例的destroy()方法
初始化阶段: 当servlet实例化时,servlet容器将调用每个servlet的init()方法来实例化每个实例,执行完每个init()方法后,servlet处于“已初始化”状态。 对于servlet对象创建的时机: 根据网上资料所说有三种:
1、Servlet容器启动时:读取web.xml配置文件中的信息,构造指定的Servlet对象,创建ServletConfig对象,同时将ServletConfig对象作为参数来调用Servlet对象的init方法。
2、在Servlet容器启动后:客户首次向Servlet发出请求,Servlet容器会判断内存中是否存在指定的Servlet对象,如果没有则创建它,然后根据客户的请求创建HttpRequest、 HttpResponse对象,从而调用Servlet 对象的service方法。
3、Servlet的类文件被更新后,重新创建Servlet Servlet容器在启动时自动创建Servlet,这是由在web.xml文件中为Servlet设置的<load-on-startup>属性决定
对于第一种开始并不了解,经查看源码知道,是在GenericServlet的init()方法里实现的,源码如下:
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
config的加载配置信息源码:
public String getInitParameter(String name) {
ServletConfig sc = this.getServletConfig();
if(sc == null) {
throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
} else {
return sc.getInitParameter(name);
}
}
public Enumeration getInitParameterNames() {
ServletConfig sc = this.getServletConfig();
if(sc == null) {
throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
} else {
return sc.getInitParameterNames();
}
}
public ServletConfig getServletConfig() {
return this.config;
}
public ServletContext getServletContext() {
ServletConfig sc = this.getServletConfig();
if(sc == null) {
throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
} else {
return sc.getServletContext();
}
}
第三种关于<load-on-statup> ...... </load-on-statup>要注意一点是:参数小于0即负数时,web容器启动时不做实例化处理,servlet首次被 调用时才做实例化,这种情况和没有设置<load-on-statup>时是一样的;参数大于0时,web容器启动时做实例化处理,顺序是从小到大,正整数小的先被实例化;参数等于0时,web容器启动时做实例处理,相当于是最大整数,因此web容器启动时,最后被实例化; 注意:在web.xml文件中配置<load-on-statup>的servlet,很可能没有配置<servlet-mapping>,这样我们无法通过url的方式访问这个servlet,这种servlet通常是需要在servlet容器启动自动加载,完成一些全局性的初始化工作
响应客户请求阶段: servlet被初始化以后,就处于能响应请求的就绪状态,每个对servlet的请求由一个Servlet Request对象代表,servlet给客户端的响应由一个servlet Response对象代表。对于用户的到达请求,服务器都会创建特定于请求的Servlet Request和servlet Response对象,然而调用被请求servlet的service()方法。service()方法从ServletRequest对象获取客户请求信息,并通过ServletResponse对象向客户返回响应信息。
ServletRequest和ServletResponse对象在HttpServlet里被强转为HttpServletRequest和HttpServletResponse,源码:
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest)req;
response = (HttpServletResponse)res;
} catch (ClassCastException var6) {
throw new ServletException("non-HTTP request or response");
}
this.service(request, response);
}
对于Service()方法,同一个Service()方法可能被多个用户同时访问,这样也会出现并发问题,所以在对同一文件的读写操作时最好加线程同步,但这样的话会降低项目的整体性能 ,具体需求具体分析
终止阶段: 当WEB应用被终止,或Servlet容器终止运行,或Servlet容器重新装载Servlet新实例时,Servlet容器会先调用Servlet的destroy()方法,在destroy()方法中可以释放掉Servlet所占用的资源。
最后说点Servlet与JSP的比较: jsp在被web容器加载后生成的class反编译后是类servlet,可以看成是servlet,jsp是直观的网页模式,servlet虽然可以生成网页,但逻辑复杂,也不直观,servlet一般用于处理业务