Servlet简述及生命周期和线程安全

   在传统Web开发中,我们处理Http请求最常用的方式是通过实现Servlet对象来进行Http请求的响应。Servlet是J2EE的重要标准之一,规定了Java如何响应Http请求规范。通过HttpServletRequest和HttpServletResponse对象,我们能够轻松地与Web容器交互。

Web容器使用servlet处理http请求
    当Web容器收到一个Http请求时,Web容器中的一个主调度线程会从事先定义好的线程中分配一个当前工作线程,将请求分配给当前的工作线程,由该线程来执行对应的servlet对象中的servce方法。当这个工作线程正在执行的时候,Web容器收到另外一个请求,主调度线程会同样从线程池中选择另外一个工作线程来服务新的请求。Web容器本身并不关心这个新的请求是否访问的是同一个Servlet实例。因此,得出: 对于同一个Servlet对象的多个请求,Servlet的service方法将在一个多线程的环境中并发执行。所以, Web容器默认采用单实例(单个servlet实例)多线程的方式来处理http请求。也就是说,Servlet对象并不是一个线程安全的对象。

Servlet的多线程机制
Servlet体系结构是建立在Java多线程机制之上的,它的生命周期是由Web容器负责的。当客户端第一次请求某个Servlet时,Servlet容器将会根据web.xml配置文件实例化这个Servlet类。当有新的客户端请求该servlet时,一般不会再实例化该servlet类,也就是有多个线程在使用这个实例,servlet容器会自动使用线程池等技术来支持系统的运行。

测试servlet多线程机制
web.xml
  <servlet>
    <servlet-name>TestServlet</servlet-name>
    <servlet-class>com.action.TestServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>TestServlet</servlet-name>
    <url-pattern>/servlet/TestServlet</url-pattern>
  </servlet-mapping>


TestServlet.java
package com.action;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class TestServlet extends HttpServlet {
	private int counter = 0;  
	public TestServlet() {
		super();
	}
	public void init() throws ServletException {
	}
	public void destroy() {
		super.destroy(); // Just puts "destroy" string in log
	}

	 public void service(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
		 
		for (int c = 0; c < 10; c++) {
			response.getWriter().println("Counter = " + counter + "<BR>");
			try {
				Thread.sleep(1000);
				counter++;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	 }
}



开两个窗口同时访问http://localhost:8080/test_t/servlet/TestServlet该servlet,会看到成员counter的增加是在多个线程同时运行。

Servlet线程安全问题主要是由实例变量造成的,因此在Servlet中应避免使用实例变量。如果应用程序设计无法避免使用实例变量,那么使用同步来保护要使用的实例变量,但为保证系统的最佳性能,应该同步可用性最小的代码路径。


servlet生命周期
servlet生命周期分为三个阶段
1、初始化阶段  调用init()方法
2、响应客户请求阶段  调用service()方法
3、终止阶段    调用destroy()方法


(1)初始化阶段
在以下时刻servlet容器装载servlet:
1.1 servlet容器启动时自动装载某些servlet,实现它只需要在web.xml文件中的<servlet></servlet>之间添加如下代码:<load-on-startup>1</load-on-startup>
1.2 在servlet容器启动后,客户首次向servlet发送请求。
1.3 servlet类文件被更新后,重新装载servlet。

servlet被装载后,servlet容器创建一个servlet实例并且调用servlet的init()方法进行初始化。 在servlet的整个生命周期内,init()方法只调用一次

(2)终止阶段
在web应用被终止,或servlet容器终止运行,或servlet容器重新装载servlet新实例时,servlet容器会先调用servlet的destroy()方法,在destroy()方法中可以释放掉servlet所占用的资源。

(3)Servlet响应请求阶段:

  对于用户到达Servlet的请求,Servlet容器会创建特定于这个请求的ServletRequest对象和ServletResponse对象,然后调用Servlet的service方法。service方法从ServletRequest对象获得客户请求信息,处理该请求,并通过ServletResponse对象向客户返回响应信息。

Servlet何时被创建:

  1,默认情况下,当WEB客户第一次请求访问某个Servlet的时候,WEB容器将创建这个Servlet的实例。

  2,当web.xml文件中如果<servlet>元素中指定了<load-on-startup>子元素时,Servlet容器在启动web服务器时,将按照顺序创建并初始化Servlet对象。

  注意:在web.xml文件中,某些Servlet只有<serlvet>元素,没有<servlet-mapping>元素,这样我们无法通过url的方式访问这些Servlet,这种Servlet通常会在<servlet>元素中配置一个<load-on-startup>子元素,让容器在启动的时候自动加载这些Servlet并调用init()方法,完成一些全局性的初始化工作。

servlet与Jsp比较:
都可以生在动态网页。
jsp的优点是擅长网页制作,生成动态页面比较直观,缺点是不容易跟踪与排错。
servlet是纯java语言,擅长于处理流程和业务逻辑,缺点是生成动态网页不直观。

猜你喜欢

转载自chentian114.iteye.com/blog/2267671
今日推荐