• java基础78 Servlet的生命周期


    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

    欢迎转载,转载务必说明出处。(如果本文对您有帮助,可以点击一下右下角的 推荐,或评论,谢谢!

  • 相关阅读:
    慕课网-安卓攻城狮视频学习及练习(二)
    慕课网-安卓攻城狮视频学习及练习(一)
    1126 Eulerian Path
    1127 ZigZagging on a Tree
    1128 N Queens Puzzle
    1129 Recommendation System
    1130 Infix Expression
    1131 Subway Map
    1132 Cut Integer
    1133 Splitting A Linked List
  • 原文地址:https://www.cnblogs.com/dshore123/p/9605400.html
Copyright © 2020-2023  润新知