1、Servlet的生命周期
简单的解析就是:
创建servlet实例(调用构造器)---->调用init()方法---->调用service()方法----->调用destroy()方法
构造方法:创建servlet时被调用,默认情况下,第一次访问servlet的时,创建servlet对象值只调用一次,证明servlet对象在tomcat是单实例.
init方法:创建玩servlet对象是调用。只调用一次
service方法:每次发送请求时被调用。调用n次(有多少次请求,就调用多少次)
destroy方法:销毁servlet对象时调用,只调用一次。(停止服务器或者重启服务器【重新部署web应用】的时候销毁servlet对象)
1.1、实例
1 package com.shore.myservlet; 2 3 4 import java.io.IOException; 5 6 import javax.servlet.ServletException; 7 import javax.servlet.http.HttpServlet; 8 import javax.servlet.http.HttpServletRequest; 9 import javax.servlet.http.HttpServletResponse; 10 11 /** 12 * @author DSHORE / 2018-9-14 13 * 14 */ 15 public class MyServletOne extends HttpServlet { 16 //构造方法 17 public MyServletOne() { 18 System.out.println("构造器被调用"); 19 } 20 21 //调用init()方法,servlet被初始化 22 public void init() throws ServletException { 23 System.out.println("调用init方法"); 24 } 25 26 //servlet服务 27 @Override 28 protected void service(HttpServletRequest arg0, HttpServletResponse arg1) 29 throws ServletException, IOException { 30 System.out.println("调用service方法"); 31 } 32 //调用destroy()方法,servlet被销毁! 33 public void destroy() { 34 System.out.println("调用destroy方法"); 35 //super.destroy(); 36 } 37 }
配置文件:web.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app version="2.5" 3 xmlns="http://java.sun.com/xml/ns/javaee" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 6 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> 7 <display-name></display-name> 8 9 <!-- servlet的配置文件 --> 10 <servlet> 11 <!--servlet内部名称(类名),可以自定义 --> 12 <servlet-name>MyServletOne</servlet-name> 13 <!-- servlet类名:包名+简单类名 --> 14 <servlet-class>com.shore.myservlet.MyServletOne</servlet-class> 15 </servlet> 16 17 <!-- servlet的映射配置 --> 18 <servlet-mapping> 19 <!-- servlet内部名称(类名),可以自定义,和上面保持一致 --> 20 <servlet-name>MyServletOne</servlet-name> 21 <!-- servlet访问名称:/名称 --> 22 <url-pattern>/MyServletOne</url-pattern> 23 </servlet-mapping> 24 25 <welcome-file-list> 26 <welcome-file>index.jsp</welcome-file> 27 </welcome-file-list> 28 </web-app>
结果图
1.2、Servlet生命周期的业务逻辑过程解析(以上面的实例作为解析案例)
浏览器 Tomcat服务器 MyServletOne对象 |
(1) 向服务器发送请求 http://localhost:8080/MyServlet/MyServletOne(可以看浏览器端的请求头信息) (2) 截取/MyServlet,进入webapps目录下的MyServlet目录。 (3) 截取/MyServletOne,去MyServlet下的web.xml文件中查找是否有匹配的<url-patten>/MyServletOne</url-patten> (4) 如果匹配,则在web.xml文件中查找是否有名称相同的servlet配置。 (5) 如果找到,则去寻找servlet配置中的servlet-class的内容:com.shore.myservlet.MyServletOne (6) 创建MyServletOne对象。 (7) 调用构造方法:public MyServletOne(){.....} (8) 构造方法被调用,创建ServletConfig对象,调用init方法 (9) init方法被调用,创建request、response对象 (10) service被调用(service根据页面传过来的的请求方式,决定调用doGet方法/doPost方法) (11) 返回被修改的response对象,并且把response对象解析成相应的格式的数据(浏览器端的响应头信息可以体现) (12) 如果服务器停止,则调用destroy方法,销毁本次servlet请求。 |
附录
1、servlet的自动加载
默认情况下,第一次访问servlet的时候创建servlet对象。如果servlet的构造方法或者init方法中执行比较多的逻辑代码,那么会导致第一次访问的时候比较慢。
解决方法:改变servlet创建对象的时机
1 <!-- servlet的配置文件 --> 2 <servlet> 3 <!--servlet内部名称(类名),可以自定义 --> 4 <servlet-name>MyServletOne</servlet-name> 5 <!-- servlet类名:包名+简单类名 --> 6 <servlet-class>com.shore.myservlet.MyServletOne</servlet-class> 7 <!-- 作用:服务器一启动,构造器和init方法就被提前加载 。 注意:整数值越大,创建优先级越低 --> 8 <load-on-startup>1</load-on-startup> 9 </servlet> 10 11 <!-- servlet的映射配置 --> 12 <servlet-mapping> 13 <!-- servlet内部名称(类名),可以自定义,和上面保持一致 --> 14 <servlet-name>MyServletOne</servlet-name> 15 <!-- servlet访问名称:/名称 --> 16 <url-pattern>/MyServletOne</url-pattern> 17 </servlet-mapping>
2、Servlet的多线程并发问题
注意:servlet对象在tomcat服务器是单实例多线程
因为servlet是多线程的,所以,当有多个servlet线程访问servlet的共享数据时,如果成员变量(即:全局变量),可能会引发线程安全问题。
解决办法:
1)把使用共享的数据代码进行同步(synchronized(锁)关键字进行同步)
2)建议在servlet类中尽量不要使用成员变量。如果确实要使用成员变量,必须同步,而且尽量缩小同步代码块的范围。(哪里使用到了成员变量就同步哪里!),以避免因为同步而导致效率降低
2.1、出现多个线程并发的例子
web.xml文件
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app version="3.0" 3 xmlns="http://java.sun.com/xml/ns/javaee" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 6 http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> 7 <display-name></display-name> 8 <servlet> 9 <servlet-name>MyServlet</servlet-name> 10 <servlet-class>com.shore.mservlet.MyServlet</servlet-class> 11 </servlet> 12 13 <servlet-mapping> 14 <servlet-name>MyServlet</servlet-name> 15 <url-pattern>/MyServlet</url-pattern> 16 </servlet-mapping> 17 <welcome-file-list> 18 <welcome-file>index.jsp</welcome-file> 19 </welcome-file-list> 20 </web-app>
MyServlet类 文件
1 package com.shore.mservlet; 2 3 import java.io.IOException; 4 import javax.servlet.ServletException; 5 import javax.servlet.http.HttpServlet; 6 import javax.servlet.http.HttpServletRequest; 7 import javax.servlet.http.HttpServletResponse; 8 9 /** 10 * @author DSHORE / 2018-9-18 11 * 12 */ 13 public class MyServlet extends HttpServlet { 14 int counnt = 1; 15 public void doGet(HttpServletRequest request, HttpServletResponse response) 16 throws ServletException, IOException { 17 response.setCharacterEncoding("GBK"); 18 response.getWriter().write("第"+counnt+"次"); 19 //睡眠5秒钟 19到25行代码的作用:测试时 更容易看出是否是线程并发问题 20 Thread thread = new Thread(); 21 try { 22 thread.sleep(5000); 23 } catch (InterruptedException e) { 24 e.printStackTrace(); 25 } 26 counnt++; 27 } 28 29 public void doPost(HttpServletRequest request, HttpServletResponse response) 30 throws ServletException, IOException { 31 doGet(request, response); 32 } 33 }
结果图
由上图,可以看出:同时出现了一个“4”,说明出现了线程问题;解决方法看下面的例子
2.2、解决多线程并发的例子
在MyServlet类中,需要共享的数据,用同步代码块 同步掉,即可。
1 package com.shore.mservlet; 2 3 import java.io.IOException; 4 import javax.servlet.ServletException; 5 import javax.servlet.http.HttpServlet; 6 import javax.servlet.http.HttpServletRequest; 7 import javax.servlet.http.HttpServletResponse; 8 9 /** 10 * @author DSHORE / 2018-9-18 11 * 12 */ 13 public class MyServlet extends HttpServlet { 14 int counnt = 1; 15 public void doGet(HttpServletRequest request, HttpServletResponse response) 16 throws ServletException, IOException { 17 response.setCharacterEncoding("GBK"); 18 synchronized (MyServlet.class) {//MyServlet.class是惟一的 19 response.getWriter().write("第"+counnt+"次"); 20 counnt++; 21 } 22 } 23 24 public void doPost(HttpServletRequest request, HttpServletResponse response) 25 throws ServletException, IOException { 26 doGet(request, response); 27 } 28 }
结果图
就算有很多个人,同时访问 也不会出现重复的数字(即:不会出现线程安全问题)
3、Servlet编程知识点
1) servlet生命周期
构造方法:创建servlet对象,默认情况下,第一次访问servlet对象时,值调用一次。
init方法(有参):创建servlet对象后调用,只调用一次。 注意:会调用无参的init方法
service方法:service提供服务的方法,每次方式请求调用。注意:request对象,response对象
destroy方法:tomcat停止或者web应用重新部署,servlet对象销毁,destroy方法被调用。
2)servletConfig对象
获取servlet的初始化参数:
getInitParameter(“name”);
getInitParameterNames();
3)servletContext对象
得到web应用路径:
Context.getContextPath();
Request.getContextPath();
得到web应用的参数:
context.getInitParameter(“name”);
context.getInitParameterNames();
域对象:
Context.setAttribute(“name”,objext); //保存数据
Context.getAttribute(“name”); //得到数据
Context.removeAttribute(“name”); //清除数据
转发:
Context.getRequestDispatcher(“路径”).forward(request,response);
Request. getRequestDispatcher(“路径”).forward(request,response);
得到web应用的资源:
Context.getRealPath(“路径”);
Context.getResourceAsStream(“路径”);
原创作者:DSHORE 作者主页:http://www.cnblogs.com/dshore123/ 原文出自:https://www.cnblogs.com/dshore123/p/9605400.html 欢迎转载,转载务必说明出处。(如果本文对您有帮助,可以点击一下右下角的 推荐,或评论,谢谢!) |