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

相关文章

MySQL中的LENGTH()函数用法详解与实例分析

《MySQL中的LENGTH()函数用法详解与实例分析》MySQLLENGTH()函数用于计算字符串的字节长度,区别于CHAR_LENGTH()的字符长度,适用于多字节字符集(如UTF-8)的数据验证... 目录1. LENGTH()函数的基本语法2. LENGTH()函数的返回值2.1 示例1:计算字符串

Javaee多线程之进程和线程之间的区别和联系(最新整理)

《Javaee多线程之进程和线程之间的区别和联系(最新整理)》进程是资源分配单位,线程是调度执行单位,共享资源更高效,创建线程五种方式:继承Thread、Runnable接口、匿名类、lambda,r... 目录进程和线程进程线程进程和线程的区别创建线程的五种写法继承Thread,重写run实现Runnab

Python实现对阿里云OSS对象存储的操作详解

《Python实现对阿里云OSS对象存储的操作详解》这篇文章主要为大家详细介绍了Python实现对阿里云OSS对象存储的操作相关知识,包括连接,上传,下载,列举等功能,感兴趣的小伙伴可以了解下... 目录一、直接使用代码二、详细使用1. 环境准备2. 初始化配置3. bucket配置创建4. 文件上传到os

使用Python实现可恢复式多线程下载器

《使用Python实现可恢复式多线程下载器》在数字时代,大文件下载已成为日常操作,本文将手把手教你用Python打造专业级下载器,实现断点续传,多线程加速,速度限制等功能,感兴趣的小伙伴可以了解下... 目录一、智能续传:从崩溃边缘抢救进度二、多线程加速:榨干网络带宽三、速度控制:做网络的好邻居四、终端交互

java向微信服务号发送消息的完整步骤实例

《java向微信服务号发送消息的完整步骤实例》:本文主要介绍java向微信服务号发送消息的相关资料,包括申请测试号获取appID/appsecret、关注公众号获取openID、配置消息模板及代码... 目录步骤1. 申请测试系统2. 公众号账号信息3. 关注测试号二维码4. 消息模板接口5. Java测试

MySQL数据库的内嵌函数和联合查询实例代码

《MySQL数据库的内嵌函数和联合查询实例代码》联合查询是一种将多个查询结果组合在一起的方法,通常使用UNION、UNIONALL、INTERSECT和EXCEPT关键字,下面:本文主要介绍MyS... 目录一.数据库的内嵌函数1.1聚合函数COUNT([DISTINCT] expr)SUM([DISTIN

SpringMVC高效获取JavaBean对象指南

《SpringMVC高效获取JavaBean对象指南》SpringMVC通过数据绑定自动将请求参数映射到JavaBean,支持表单、URL及JSON数据,需用@ModelAttribute、@Requ... 目录Spring MVC 获取 JavaBean 对象指南核心机制:数据绑定实现步骤1. 定义 Ja

Python打印对象所有属性和值的方法小结

《Python打印对象所有属性和值的方法小结》在Python开发过程中,调试代码时经常需要查看对象的当前状态,也就是对象的所有属性和对应的值,然而,Python并没有像PHP的print_r那样直接提... 目录python中打印对象所有属性和值的方法实现步骤1. 使用vars()和pprint()2. 使

Python实例题之pygame开发打飞机游戏实例代码

《Python实例题之pygame开发打飞机游戏实例代码》对于python的学习者,能够写出一个飞机大战的程序代码,是不是感觉到非常的开心,:本文主要介绍Python实例题之pygame开发打飞机... 目录题目pygame-aircraft-game使用 Pygame 开发的打飞机游戏脚本代码解释初始化部

MySQL JSON 查询中的对象与数组技巧及查询示例

《MySQLJSON查询中的对象与数组技巧及查询示例》MySQL中JSON对象和JSON数组查询的详细介绍及带有WHERE条件的查询示例,本文给大家介绍的非常详细,mysqljson查询示例相关知... 目录jsON 对象查询1. JSON_CONTAINS2. JSON_EXTRACT3. JSON_TA