小博老师解析Java核心技术点 ——Servlet生命周期

来源:互联网 发布:java发送邮件到qq邮箱 编辑:程序博客网 时间:2024/05/29 17:31

[理论知识]

我们在学习JavaEE企业级开发的初期,经常会遇到有关于Servlet生命周期的问题,这方面的理论知识网上有详尽的介绍,但是光理解理论概念以及Servlet生命周期的执行顺序是不够的。

[步骤解读一]Servlet生命周期

小博老师先为大家演示一下基本Servlet的生命周期,核心代码如下:

@WebServlet("/BWF01")

public class BWF01Servlet extends HttpServlet {

public BWF01Servlet(){

System.out.println("BWF01 -> constructor() has been called!");

}

public void init()throws ServletException {

System.out.println("BWF01 -> init() has been called!");

super.init();

}

public void service(ServletRequestrequest, ServletResponse response) throws ServletException, IOException {

System.out.println("BWF01 -> service() has been called!");

super.service(request,response);

}

protected void doGet(HttpServletRequestrequest, HttpServletResponse response) throws ServletException, IOException {

System.out.println("BWF01 -> doGet() has been called!");

}

protected void doPost(HttpServletRequestrequest, HttpServletResponse response) throws ServletException, IOException {

System.out.println("BWF01 -> doPost() has been called!");

}

public void destroy() {

System.out.println("BWF01 -> destroy() has been called!");

super.destroy();

}

}

开启服务器,第一次访问该Servlet后的执行顺序如下:

BWF01 -> constructor() has been called!

BWF01 -> init() has been called!

BWF01 -> service() has been called!

BWF01 -> doGet() has been called!

 

但是当我们后续再访问该Servlet时,执行顺序则只剩下:

BWF01 -> service() has been called!

BWF01 -> doGet() has been called!

由此可见,Servlet是单例的,只有在第一次被访问时会实例化对象,并且调用init()初始化参数方法,访问后对象没有被销毁(不调用destroy()方法)。只有当服务器关闭时,会调用destroy()方法销毁Servlet对象。

[步骤解读二]Servlet的实现是单例、多线程

接下来我们修改Servlet中的doGet()方法,核心代码如下:

protected void doGet(HttpServletRequestrequest, HttpServletResponse response) throws ServletException, IOException {

System.out.println("BWF01 -> doGet() has been called!");

System.out.println("BWF01 -> threadId = " + Thread.currentThread().getId());

}

通过浏览器多次访问该Servlet,发现每一次的threadId都是不相同的。这说明服务器对于多次客户端请求同一个Servlet,会创建一个子线程来处理,这些子线程共享同一个Servlet对象。

[步骤解读三]Servlet线程安全

我们再次修改此Servlet中的doGet()方法,核心代码如下:

private int times = 0;  // 累加访问次数

protected void doGet(HttpServletRequestrequest, HttpServletResponse response) throws ServletException, IOException {

System.out.println("BWF01 -> doGet() has been called!");

System.out.println("BWF01 -> times = " +times);

}

我们打开多个浏览器,多次访问该Servlet,发现不同的客户端浏览器访问Servlet时,成员属性times的值会累加。这是因为Servlet是单例的,虽然多个客户端每次访问,会在不同的线程中处理,但是Servlet的对象只有一份,因此成员属性也只有一份。由此可见对于Servlet来说,成员属性时线程不安全的,所以我们想要实现线程安全的数据存储,建议采用HttpServletRequest对象、HttpSession对象等。

0 0