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

相关文章

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

C++操作符重载实例(独立函数)

C++操作符重载实例,我们把坐标值CVector的加法进行重载,计算c3=c1+c2时,也就是计算x3=x1+x2,y3=y1+y2,今天我们以独立函数的方式重载操作符+(加号),以下是C++代码: c1802.cpp源代码: D:\YcjWork\CppTour>vim c1802.cpp #include <iostream>using namespace std;/*** 以独立函数

实例:如何统计当前主机的连接状态和连接数

统计当前主机的连接状态和连接数 在 Linux 中,可使用 ss 命令来查看主机的网络连接状态。以下是统计当前主机连接状态和连接主机数量的具体操作。 1. 统计当前主机的连接状态 使用 ss 命令结合 grep、cut、sort 和 uniq 命令来统计当前主机的 TCP 连接状态。 ss -nta | grep -v '^State' | cut -d " " -f 1 | sort |

多线程解析报表

假如有这样一个需求,当我们需要解析一个Excel里多个sheet的数据时,可以考虑使用多线程,每个线程解析一个sheet里的数据,等到所有的sheet都解析完之后,程序需要提示解析完成。 Way1 join import java.time.LocalTime;public class Main {public static void main(String[] args) thro

Java第二阶段---09类和对象---第三节 构造方法

第三节 构造方法 1.概念 构造方法是一种特殊的方法,主要用于创建对象以及完成对象的属性初始化操作。构造方法不能被对象调用。 2.语法 //[]中内容可有可无 访问修饰符 类名([参数列表]){ } 3.示例 public class Car {     //车特征(属性)     public String name;//车名   可以直接拿来用 说明它有初始值     pu

Maven(插件配置和生命周期的绑定)

1.这篇文章很好,介绍的maven插件的。 2.maven的source插件为例,可以把源代码打成包。 Goals Overview就可以查看该插件下面所有的目标。 这里我们要使用的是source:jar-no-fork。 3.查看source插件的example,然后配置到riil-collect.xml中。  <build>   <plugins>    <pl

Java Websocket实例【服务端与客户端实现全双工通讯】

Java Websocket实例【服务端与客户端实现全双工通讯】 现很多网站为了实现即时通讯,所用的技术都是轮询(polling)。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发 出HTTP request,然后由服务器返回最新的数据给客服端的浏览器。这种传统的HTTP request 的模式带来很明显的缺点 – 浏 览器需要不断的向服务器发出请求,然而HTTP

Java 多线程概述

多线程技术概述   1.线程与进程 进程:内存中运行的应用程序,每个进程都拥有一个独立的内存空间。线程:是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换、并发执行,一个进程最少有一个线程,线程实际数是在进程基础之上的进一步划分,一个进程启动之后,进程之中的若干执行路径又可以划分成若干个线程 2.线程的调度 分时调度:所有线程轮流使用CPU的使用权,平均分配时间抢占式调度

Java 多线程的基本方式

Java 多线程的基本方式 基础实现两种方式: 通过实现Callable 接口方式(可得到返回值):

JavaEE7 Servlet 3.1(JSR 340)规范中文版

http://www.iteye.com/news/27727-jinnianshilongnian     Jave EE 7中的部分规范已正式获得批准通过,其中包括JSR340 Java Servlet 3.1规范,去年翻译了该规范,在此分享出来,希望对某些朋友有所帮助,不足之处请指正。   点击直接下载    在线版目录   Servlet3.1规范翻译