Servlet 生命周期

1. 生命周期方法

默认情况下,当用户第一次发起请求,Tomcat会根据URI创建对应的Servlet,将Servlet加载到堆内存中,执行构造方法和init()

之后,Servlet一直驻留在堆内存中,直到当前应用被关闭,执行destory()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class MyServlet extends HttpServlet {
/** Servlet被实例化时调用 */
public MyServlet() {
System.out.println("MyServlet()");
}

/** 实例化之后,执行init */
@Override
public void init() throws ServletException {
System.out.println("init");
}

/** Servlet销毁之前,执行destory */
@Override
public void destroy() {
System.out.println("destory");
}

/** 访问当前Servlet时,执行service */
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.getWriter().write("<h1>HelloWorld</h1>");
}
}

2. 实例化Servlet的时机

可以通过配置loadOnStartup,来改变Servlet实例化的时机,分以下3种情况

  • loadOnStartup < 0:即负数的情况下,web容器启动的时候不做实例化处理,servlet首次被调用时做实例化。这种情况和没有设置loadOnStartup是一样的
  • loadOnStartup > 0:web容器启动的时候做实例化处理,顺序是由小到大,正整数小的先被实例化
  • loadOnStartup = 0:web容器启动的时候做实例化处理,相当于是最大整数,因此web容器启动时,最后被实例
1
2
3
4
5
<servlet>
<servlet-name>haha</servlet-name>
<servlet-class>demo.servlet.MyServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

3. Servlet线程安全问题

从Servlet的生命周期可以看出,Servlet是单例的

这说明多个用户同时访问时,可能存在线程安全问题

为了避免发生线程安全问题,要使用变量时,尽量定义局部变量,而不要使用成员变量。因为局部变量在栈中,多个线程的栈是不共享的。

如果定义了成员变量,仅仅是读取,那是可以的,但是千万不要去修改

1
2
3
4
5
6
7
8
9
public class MyServlet extends HttpServlet {
private Integer age = 100; // 尽量不定义成员变量

@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
int age = 100; // 尽量使用局部变量
}
}

panchaoxin wechat
关注我的公众号
支持一下