原文同步发表至个人博客【夜月归途】
原文链接:http://www.guitu18.com/se/java/2018-07-22/19.html
出处: http://www.guitu18.com/
本博客中未标明转载的文章归作者 夜月归途和博客园所有。 欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
Servlet生命周期和加载机制
查看Servlet3.1源码,其接口定义如下:
package javax.servlet; public interface Servlet { public void init(ServletConfig config) throws ServletException; public ServletConfig getServletConfig(); public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException; public String getServletInfo(); public void destroy(); }
init(ServletConfig config);
init方法在容器启动时会被容器调用,且只会被调用一次;
调用的时机是跟Servlet的配置项'load-on-startup'有关系的;
<servlet> <servlet-name>springmvcdemoservlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class> <init-param> <param-name>contextConfigLocationparam-name> <param-value>classpath:springmvc.xmlparam-value> init-param> <load-on-startup>1load-on-startup> servlet>
init方法的参数,是容器传进去的;我们在web.xml中配置的contextConfigLocation参数,就保存在ServletConfig中;
这项参数我们不配置的话,它有默认值:WEB-INF/${ServletName}-servlet.xml,变量${ServletName}是xml中配置的'servlet-name';
getServletConfig();
getServletConfig方法用于获取ServletConfig;
service(ServletRequest req, ServletResponse res);
service方法用于具体处理一个请求;每次访问,都会执行一次,server方法内部会根据请求方式的不同,调用不同的doXXX方法;
getServletInfo();
getServletInfo方法可以获取一些Servlet相关的信息,如作者、版权等;这个方法需要自己实现,默认返回空字符串;
destroy();
destroy方法主要用于Servlet销毁时释放资源,同init一样只会被调用一次;
Servlet生命周期测试demo
-
新建web工程,创建三个都实现Servlet接口的ServletDemo对象;
这里创建的分别是Servlet1,Servlet2,Servlet3,代码都是一样的只贴上Servlet1的代码;package com.guitu18.servlet; 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 Servlet_1 implements Servlet { @Override public void destroy() { System.out.println("Servlet_1:destroy()执行销毁..."); } @Override public ServletConfig getServletConfig() { return null; } @Override public String getServletInfo() { return null; } @Override public void init(ServletConfig arg0) throws ServletException { System.out.println("Servlet_1:init()执行初始化..."); } @Override public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException { System.out.println("Servlet_1:service()执行中..."); } }
-
web.xml配置如下:
<servlet> <servlet-name>servlet_1servlet-name> <servlet-class>com.guitu18.servlet.Servlet_1servlet-class> servlet> <servlet-mapping> <servlet-name>servlet_1servlet-name> <url-pattern>/servlet_1url-pattern> servlet-mapping> <servlet> <servlet-name>servlet_2servlet-name> <servlet-class>com.guitu18.servlet.Servlet_2servlet-class> <load-on-startup>2load-on-startup> servlet> <servlet-mapping> <servlet-name>servlet_2servlet-name> <url-pattern>*.guitu18url-pattern> servlet-mapping> <servlet> <servlet-name>servlet_3servlet-name> <servlet-class>com.guitu18.servlet.Servlet_3servlet-class> <load-on-startup>1load-on-startup> servlet> <servlet-mapping> <servlet-name>servlet_3servlet-name> <url-pattern>/abc/*url-pattern> servlet-mapping> <servlet-mapping> <servlet-name>servlet_2servlet-name> <url-pattern>/servlet_4url-pattern> servlet-mapping>
我在xml中分别配置了这三个Servlet,配置了4个servlet-mapping,其中'/servlet2.guitu'和'/servlet4'都是指向servle_2的;
这里就涉及到Servlet中的配置方式了,一共有3种: - 完全路径匹配
以'/'开始;比如:/servlet_1 - 目录匹配
以'/'开始,以'/'结束;比如:/abc/ - 扩展名匹配
不能以'/'开始,要以''开始;比如:.guitu18
为了是匹配时不产歧义,这三种匹配方式是有优先级的:
完全路径匹配 > 目录匹配 > 扩展名匹配 - 完全路径匹配
-
启动项目:
因为Servlet2和Servlet3都配置了项,且配置的值不小于0,所以在项目启动时,Servlet2和Servlet3就会被初始化,控制台输出: Servlet_3:init()执行初始化... Servlet_2:init()执行初始化...
这里看出,Servlet3比Servlet2有限初始化,因为Servlet_3配置的
的值比Servlet2小,所以优先被加载;Servlet1因为没有配置 所以只有其第一次被访问时才会被加载初始化; 访问Servlet1的地址:http://localhost:8080/servletdemo/servlet1
Servlet_1:init()执行初始化... Servlet_1:service()执行中...
此时Servlet_1才被初始化;
-
Servlet对象销毁 现在关闭Tomcat服务,Servlet对象会被销毁;
Servlet_2:destroy()执行销毁... Servlet_3:destroy()执行销毁... Servlet_1:destroy()执行销毁...
可以看出销毁的顺序和加载的顺序相同,优先被加载的也会最先被销毁;