Servlet的生命周期、单实例多线程和ServletConfig对象

2024-01-12 05:32

本文主要是介绍Servlet的生命周期、单实例多线程和ServletConfig对象,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.Servlet的生命周期

/*** Servlet的生命周期*init(ServletConfig config):初始化。当该Servlet第一次被请求时,Servlet会调用该方法,后续请求不会再被调用。可以利用该方法进行相应的初始化功能。* service(ServletRequest req,ServletResponse res)每当请求Servlet时,Servlet都会调用此方法。* destroy():销毁当要销毁Servlet时,Servlet容器就会调用该方法。通常在卸载程序,或者关闭Servlet容器就会调用销毁方法,一般在该方法中写清除数据的代码。* Servlet的线程安全性:Servlet实例会被一个应用程序中的所有用户共享,因此不建议使用类级别比哪里,除非它们是只读的或只修改的。*/
package com.xunpu.a_life;import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class LifeDemo extends HttpServlet {//无参构造public LifeDemo(){System.out.println("Servlet对象被创建了。。。");}//    /**
//     * 用户在登录成功之前,应该先初始化一下用户登录次数
//     * @throws ServletException
//     */
//    @Override
//    public void init() throws ServletException {
//        super.init();
//    }@Overridepublic void init(ServletConfig config) throws ServletException {System.out.println("Servlet被初始化了。。。");}@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("Servlet的业务服务方法被调用了。。。");}@Overridepublic void destroy() {System.out.println("Servlet被销毁。。。");}
}

在浏览器中输入localhost:8080/life,回车,结果如图:

如果再次输入两次,并回车。结果如图:

这说明Servlet对象只会初始化、创建一次。而每启动一次life文件,service()就会执行一次。

当暂停服务器,点击下图的红色按钮暂停服务器时,Servlet对象才会被销毁。

tomcat服务器挂掉的原因:

1)System.exit(0);//jvm停止运行.  2)没电

在具体执行业务的时候,不会去覆盖service(),而是去覆写其中的doGet()和doPost()。service()中有doGet/doPost/doHeader/doPut等等方法。

2.Servlet对象创建的过程

servlet对象被创建的过程,其实是一种反射机制
1)tomcat服务器启动的时候,web.xml中先找到url-pattern:/life
2)再去servlet-mapping中寻找servlet-name中寻找LifeDemo
3)在servlet的配置信息中寻找LifeDemo
4)通过Class的forName("com.xunpu.a_life.LifeDemo"):获取字节码文件对象。

反射的伪代码:

	//创建了当前的类对象Class classz=Class.forName("com.xunpu.a_life.LifeDemo");//通过获取Constructor对象Constructor con=classz.getDeclaredConstructor();LifeDemo obj=con.newInstance();//获取加载init()Method m1=classz.getMethod("init",ServletConfig.class);m1.invoke(obj,config);//调用//调用服务方法Method m2=classz.getDeclaredMethod("service",HttpServletRequest.class,HttpServletResponse.class);m2.invoke(obj,request,response)

获取反射对象的方式(获取字节码文件对象的方式):

	1)Class.forName("包名.类名")2)数据类型的class属性  String.class3)Object类对象的getClass()-->Class对象
推荐使用第一种,加载的是一种字符串(配置文件)

3.Servlet的架构体系

4.init方法的使用

package com.xunpu.b_init;import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** init方法的使用**/
public class InitDemo extends HttpServlet {/*** servlet的生命周期的初始化方法* @param config  servlet的配置信息:初始化参数 或者Servlet的加载机制* @throws ServletException*/@Overridepublic void init(ServletConfig config) throws ServletException {//这个方法是获取配置信息时使用的}/*** 是Servlet初始化的简便方法(用户自定义初始化的时候去使用)* @throws ServletException*/@Overridepublic void init() throws ServletException {//获取用户session数据-->初始化用户的登录次数、登录状态}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}
}

5.Servlet--单实例多线程

请看下面的代码:

package com.xunpu.c_thread;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;public class ThreadDemo extends HttpServlet {private static int count=1;protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;charset=utf-8");try {method(response);} catch (InterruptedException e) {e.printStackTrace();}}private void method(HttpServletResponse response) throws IOException, InterruptedException {response.getWriter().write("您当前是第"+count+"个访客");//为了模拟多线程访问场景,先让线程休眠3秒钟Thread.sleep(3000);this.count++;}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}
}

如果此时有两个浏览器访问 http://localhost:8080/threadDemo,如IE(Thread1)   谷歌(Thread2),则可能发生线程安全问题。

检验多线程安全的标准:
1)是否是多线程环境:servlet的多线程环境(多个浏览器访问)
2)是否有共享数据
3)是否有多条语句对共享数据进行操作

解决方案:

将3)多条语句共享数据的操作使用同步代码块包含起来。

同步锁锁的对象:

1)可以任意的Java对象
2)如果使用同步方法(非静态的),锁对象就是this。(一般情况)
3)如果使用静态的同步方法,锁对象类名.class

同步锁解决线程安全问题(可能出现死锁问题)

本题的解决方法一:使用synchronized锁住ThreadDemo的类对象

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;charset=utf-8");synchronized (ThreadDemo.class) {try {method(response);} catch (InterruptedException e) {e.printStackTrace();}}}

解决方法二:使用静态的同步method方法。

    private static synchronized void method(HttpServletResponse response) throws IOException, InterruptedException {response.getWriter().write("您当前是第"+count+"个访客");//为了模拟多线程访问场景,先让线程休眠3秒钟Thread.sleep(3000);count++;}

6.ServletConfig对象

当Servlet容器初始化Servlet时,Servlet容器会给Servlet的init()传入一个ServletConfig。ServletConfig封装可以通过部署描述符传给Servlet的配置信息。这样传入的每一条信息就叫做初始化参数,一个初始化参数由key和value组成。

需求:如果要读取E盘下的aaa.txt文件,并将文件的内容在后台输出。代码为:

package com.xunpu.d_config;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;/*** ServletConfig对象:Servlet的配置对象*/
public class ConfigDemo extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//有一个需求:读取e盘下的aaa.txt文件,将内容输出//如果文件变为bbb.txtBufferedReader br=new BufferedReader(new FileReader("e://aaa.txt"));String line=null;while((line=br.readLine())!=null){System.out.println(line);}//释放资源br.close();}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}
}

此时如果变更需求,读取的是bbb.txt文件,怎么写? 

业务中的内容--->频繁更改业务中的内容---->放入到Servlet的配置信息中的一个初始化参数中

方法一:在web.xml文件中指定ConfigDemo的初始化参数,然后通过ServletConfig对象获取该参数的值,把path值传入File中。这样,只要修改web.xml中的参数值,就可以读取不同的文件,避免修改业务(doGet方法)

  web.xml有关ConfigDemo的配置信息:<servlet><servlet-name>ConfigDemo</servlet-name><servlet-class>com.xunpu.d_config.ConfigDemo</servlet-class><!--Servlet的初始化参数初始化参数可以有多个,但是名称不能重复--><init-param><param-name>path</param-name><param-value>e:/aaa.txt</param-value></init-param></servlet><servlet-mapping><servlet-name>ConfigDemo</servlet-name><url-pattern>/configDemo</url-pattern></servlet-mapping>
package com.xunpu.d_config;import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.net.ServerSocket;
/*** ServletConfig对象:Servlet的配置对象* 一个Servlet中可以使用多个ServletConfig对象*/
public class ConfigDemo extends HttpServlet {//声明一个ServletConfig对象private ServletConfig config;private String path=null;@Overridepublic void init(ServletConfig config) throws ServletException {this.config=config;path = config.getInitParameter("path");//从webb.xml中获取path的值。}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {BufferedReader br=new BufferedReader(new FileReader(path));String line=null;while((line=br.readLine())!=null){System.out.println(line);}//释放资源br.close();}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}
}

这种方法也较麻烦,采用下面的方式。

方式二:根据HttpServlet父类的public ServletConfig getServletConfig()方法直接获取到ServletConfig对象。

package com.xunpu.d_config;import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.net.ServerSocket;
/*** ServletConfig对象:Servlet的配置对象* 一个Servlet中可以使用多个ServletConfig对象*/
public class ConfigDemo extends HttpServlet {//声明一个ServletConfig对象private ServletConfig config;protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {/**HttpServlet的父类GenericServlet源码:*  private transient ServletConfig config;*    public ServletConfig getServletConfig() {*         return this.config;*     }*/ServletConfig config=this.getServletConfig();String path=config.getInitParameter("path");BufferedReader br=new BufferedReader(new FileReader(path));String line=null;while((line=br.readLine())!=null){System.out.println(line);}//释放资源br.close();}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}
}

7.配置Servlet的加载时机

Servlet的加载时机:
          一般情况下,默认没有设置load-on-startup时,访问servlet的时候被tomcat创建
          如果设置了,就是在tomcat启动的时候 加载。数字越大,优先级越低。

在案例1中,如果设置了load-on-starup,设置格式如下:

   <!--servlet的配置信息--><servlet><servlet-name>LifeDemo</servlet-name><servlet-class>com.xunpu.a_life.LifeDemo</servlet-class><!--tomcat启动的时候,servlet对象就被创建了--><load-on-startup>2</load-on-startup></servlet><!--servlet的映射信息--><servlet-mapping><servlet-name>LifeDemo</servlet-name><url-pattern>/lifeDemo</url-pattern></servlet-mapping>

那么不必在浏览器中访问lifeDemo,当启动tomcat服务器时,就会打印

这篇关于Servlet的生命周期、单实例多线程和ServletConfig对象的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/596943

相关文章

C# WinForms存储过程操作数据库的实例讲解

《C#WinForms存储过程操作数据库的实例讲解》:本文主要介绍C#WinForms存储过程操作数据库的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、存储过程基础二、C# 调用流程1. 数据库连接配置2. 执行存储过程(增删改)3. 查询数据三、事务处

springboot security验证码的登录实例

《springbootsecurity验证码的登录实例》:本文主要介绍springbootsecurity验证码的登录实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录前言代码示例引入依赖定义验证码生成器定义获取验证码及认证接口测试获取验证码登录总结前言在spring

在java中如何将inputStream对象转换为File对象(不生成本地文件)

《在java中如何将inputStream对象转换为File对象(不生成本地文件)》:本文主要介绍在java中如何将inputStream对象转换为File对象(不生成本地文件),具有很好的参考价... 目录需求说明问题解决总结需求说明在后端中通过POI生成Excel文件流,将输出流(outputStre

tomcat多实例部署的项目实践

《tomcat多实例部署的项目实践》Tomcat多实例是指在一台设备上运行多个Tomcat服务,这些Tomcat相互独立,本文主要介绍了tomcat多实例部署的项目实践,具有一定的参考价值,感兴趣的可... 目录1.创建项目目录,测试文China编程件2js.创建实例的安装目录3.准备实例的配置文件4.编辑实例的

python+opencv处理颜色之将目标颜色转换实例代码

《python+opencv处理颜色之将目标颜色转换实例代码》OpenCV是一个的跨平台计算机视觉库,可以运行在Linux、Windows和MacOS操作系统上,:本文主要介绍python+ope... 目录下面是代码+ 效果 + 解释转HSV: 关于颜色总是要转HSV的掩膜再标注总结 目标:将红色的部分滤

Java使用多线程处理未知任务数的方案介绍

《Java使用多线程处理未知任务数的方案介绍》这篇文章主要为大家详细介绍了Java如何使用多线程实现处理未知任务数,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 知道任务个数,你可以定义好线程数规则,生成线程数去跑代码说明:1.虚拟线程池:使用 Executors.newVir

Spring 中使用反射创建 Bean 实例的几种方式

《Spring中使用反射创建Bean实例的几种方式》文章介绍了在Spring框架中如何使用反射来创建Bean实例,包括使用Class.newInstance()、Constructor.newI... 目录1. 使用 Class.newInstance() (仅限无参构造函数):2. 使用 Construc

C#原型模式之如何通过克隆对象来优化创建过程

《C#原型模式之如何通过克隆对象来优化创建过程》原型模式是一种创建型设计模式,通过克隆现有对象来创建新对象,避免重复的创建成本和复杂的初始化过程,它适用于对象创建过程复杂、需要大量相似对象或避免重复初... 目录什么是原型模式?原型模式的工作原理C#中如何实现原型模式?1. 定义原型接口2. 实现原型接口3

JAVA封装多线程实现的方式及原理

《JAVA封装多线程实现的方式及原理》:本文主要介绍Java中封装多线程的原理和常见方式,通过封装可以简化多线程的使用,提高安全性,并增强代码的可维护性和可扩展性,需要的朋友可以参考下... 目录前言一、封装的目标二、常见的封装方式及原理总结前言在 Java 中,封装多线程的原理主要围绕着将多线程相关的操

MyBatis-Plus中Service接口的lambdaUpdate用法及实例分析

《MyBatis-Plus中Service接口的lambdaUpdate用法及实例分析》本文将详细讲解MyBatis-Plus中的lambdaUpdate用法,并提供丰富的案例来帮助读者更好地理解和应... 目录深入探索MyBATis-Plus中Service接口的lambdaUpdate用法及示例案例背景