Servlet生命周期分为四个阶段:
1:构造方法: 创建servlet对象的时候调用。默认情况下,第一次访问servlet的时候创建servlet对象只调用1次。证明servlet对象在tomcat是单实例的。
2:init方法: 创建完servlet对象的时候调用。只调用1次。
3:service方法: 每次发出请求时调用。调用n次。
4:destroy方法: 销毁servlet对象的时候调用。停止服务器或者重新部署web应用时销毁servlet对象。只调用1次。
public class ServletDemo {
/**
* 伪代码演示servlet的生命周期
Tomtcat内部代码运行:
1)通过映射找到到servlet-class的内容,字符串: cn.itcats.MyServlet
2)通过反射构造MyServlet对象*/
//1、得到字节码对象
Class clazz = Class.forName("cn.itcats.MyServlet");
//2、调用无参数的构造方法来构造对象
Object obj = clazz.newInstance(); //servlet的构造方法被调用
//3、创建ServletConfig对象,通过反射调用init方法
//3.1、得到方法对象
Method init = clazz.getDeclareMethod("init",ServletConfig.class);
//3.2 调用方法
init.invoke(obj,config); //servlet的init方法被调用
//4、创建request,response对象,通过反射调用service方法
//4.1 得到方法对象
Method service = clazz.getDeclareMethod("service",HttpServletRequest.class,HttpServletResponse.class);
//4.2 调用方法
service.invoke(obj,request,response); //servlet的service方法被调用
//5、当tomcat服务器停止或web应用重新部署,通过反射调用destroy方法
//5.1 得到方法对象
Method destroy = clazz.getDeclareMethod("destroy",null);
//5.2 调用方法
destroy.invoke(obj,null); //servlet的destroy方法被调用
}
Servlet执行流程:
1、读取web.xml文件解析servlet
2、使用java的反射机制初始化servlet类
3、当发起servlet请求时候调用了HttpServlet父类service方法
4、通过service方法判断请求方式
5、子类重写了doGet方法,调用子类doGet方法
service和doGet方法有什么区别?
当发起servlet请求时,通过HttpServlet类的service方法判断请求方式,若为get请求,调用子类的doGet方法。
Servlet的多线程并发问题
注意: servlet对象在tomcat服务器是单实例多线程的。
由于通过反射机制,通过web.xml初始化类,默认调用无参构造函数,可以在自定义的Servlet类书写无参构造函数证明。
因为servlet是多线程的,所以当多个servlet的线程同时访问了servlet的共享数据,如成员变量,可能会引发线程安全问题。
解决办法:
1)把使用到共享数据的代码块进行同步(使用synchronized关键字进行同步)
2)建议在servlet类中尽量不要使用成员变量。如果确实要使用成员,必须同步。而且尽量缩小同步代码块的范围。(哪里使用到了成员变量,就同步哪里!!),以避免因为同步而导致并发效率降低。