本文主要是介绍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对象的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!