Servlet生命周期以及线程安全问题

目录

一、什么是Servlet

二、Servlet的生命周期

        1、加载并实例化

        2、初始化(执行一次)

        3、请求处理(反复执行)

        4、销毁(执行一次)

三、线程安全问题


一、什么是Servlet

        Servlet是在服务端运行的Java程序,可以接受客户端请求并作出响应。

简单的来说 就是将一个静态页面变为动态页面

        Servlet 通过一个定义良好的生命周期来进行管理,该生命周期规定了 Servlet 如何被加载、实例化、初始化、 处理客户端请求,以及何时结束服务(销毁)。

二、Servlet的生命周期

         Servlet的生命周期有四个阶段:加载并实例化、初始化、请求处理、销毁。主要涉及到的方法有initservicedoGetdoPostdestory

        1、加载并实例化

        Servlet容器负责加载和实例化Servelt。当Servlet容器启动时,或者在容器检测到需要这个Servlet来响应第一个请求时,创建Servlet实例。当Servlet容器启动后,Servlet通过类加载器来加载Servlet类,加载完成后再new一个Servlet对象来完成实例化。

        2、初始化(执行一次)

        在Servlet实例化之后,容器将调用init()方法,并传递实现ServletConfig接口的对象。在init()方法中,Servlet可以部署描述符中读取配置参数,或者执行任何其他一次性活动。在Servlet的整个生命周期类,init()方法只被调用一次。

@WebServlet("/BaseServlet")
public class BaseServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	protected TemplateEngine templateEngine;  // 模板引擎
	protected ServletContextTemplateResolver templateResolver; //模板解析器
   
    @Override
    public void init() throws ServletException {
        super.init();
        templateEngine = new TemplateEngine();
        templateResolver = new ServletContextTemplateResolver(getServletContext());
        //设置要应用于此解析器解析的模板的模板模式。
        templateResolver.setTemplateMode("HTML5"); 
        //非严格的HTML5
//      templateResolver.setTemplateMode("LEGACYHTML5");
        // 设置新的字符编码以读取模板资源。
        templateResolver.setCharacterEncoding("utf-8");
        // 设置要添加到所有模板名称的新(可选)前缀,以将模板名称转换为资源名称。
        templateResolver.setPrefix("/");
        //设置要添加到所有模板名称的新(可选)后缀,以将模板名称转换为资源名称。
        templateResolver.setSuffix(".html"); 
        //将模板缓存关闭,默认是true
        templateResolver.setCacheable(false);
        //给模板引擎设置模板解析器
        templateEngine.setTemplateResolver(templateResolver);
    }
	
	
}

        3、请求处理(反复执行)

        当Servlet初始化后,容器就可以准备处理客户机请求了。当容器收到对这一Servlet的请求,就调用Servlet的service()方法,并把请求和响应对象作为参数传递。当并行的请求到来时,多个service()方法能够同时运行在独立的线程中。service()方法检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用 doGet()doPost()等方法。

/**
 * Servlet implementation class aaa
 */
@WebServlet("/aaa")
public class aaa extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
//无参构造
    public aaa() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		response.getWriter().append("Served at: ").append(request.getContextPath());
        写代码
        处理乱码
        获取资源
        数据
        响应用户
	
}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

        4、销毁(执行一次)

        一旦Servlet容器检测到一个Servlet要被卸载,这可能是因为要回收资源或者因为它正在被关闭,容器会在所有Servlet的service()线程之后,调用Servlet的destroy()方法。然后,Servlet就可以进行无用存储单元收集清理。这样Servlet对象就被销毁了。这四个阶段共同决定了Servlet的生命周期。

         该生命周期通过javax.servlet.Servlet 接口中的 initservice 和 destroy 这些 API 来表示,所有 Servlet 必须直接或间接的实现HttpServlet 抽象类。

三、线程安全问题

                Servlet容器通过维护一个线程池来处理多个请求,线程池中维护的是一组工作者线程(Worker Thread)。Servlet容器通过一个调度线程(Dispatcher Thread)来调度线程池中的线程。

                当客户端的servlet请求到来时,调度线程会从线程池中选出一个工作者线程并将请求传递给该线程,该线程就会执行对应servlet实例的service方法。同样,当客户端发起另一个servlet请求时,调度线程会从线程池中选出另一个线程去执行servlet实例的service方法。Servlet容器并不关心这些线程访问的是同一个servlet还是不同的servlet,当多个线程访问同一个servlet时,该servlet实例的service方法将在多个线性中并发执行。

        简单的来说就是在多个请求下访问的是同一个Servlet实例对象

所以,Servlet对象是单实例多线程,Servlet不是线程安全的

举个例子:

public class aaaServlet extends HttpServlet{
 private static final long serialVersionUID = 1L;
 
 private String username1 = null;//实例变量
 
 @Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp)
         throws ServletException, IOException{
  username1 = request.getParameter("username1");
 
  String username2 = request.getParameter("username2");//局部变量

 }
}

username1则是共享变量,多个线程会同时访问该变量,是线程不安全的。

username2是局部变量,不管多少个线程同时访问,都是线程安全的。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值