• JavaWeb之 Servlet执行过程 与 生命周期


    Servlet的概念

    什么是Servlet呢?

      Java中有一个叫Servlet的接口,如果一个普通的类实现了这个接口,这个类就是一个Servlet。Servlet下有一个实现类叫HttpServlet,一个普通的java如果继承了HttpServlet类,覆盖了它的doGet和doPost方法,那么这个普通类也可以叫做Servlet。最后,servlet程序交给服务器运行!

      那么,当我们写好了一个Servlet,交给了服务器,它是如何执行的呢!?

    Servlet的执行过程

    我们写了一个Servlet名叫hello。那么浏览器是如何访问到这个资源呢?

    要说这个,我们先来学习一下浏览器的地址输入。

      有这样一个输入:   http://localhost:8080/day10/hello

    http:    http协议

    localhost:   域名,到本地C盘下的hosts文件查找是否存在域名对应的ip映射记录地址。有的话就直接访问该IP,没有的话就到DNS上去找。

    8080        端口号,这里指tomcat服务器。localhost匹配到tomcat的默认站点,到webapps目录下找web应用。

    /day10      web应用的名称。在webapps下找是否存在day10的目录。

    /hello       web资源。在day10web应用下查找是否有这个资源。(如果看不懂,最好先去了解一下tomcat里的文件结构。)

     

        这里/hello 资源就是我们写的一个Servlet,服务器得到这个字符串后就是经过以下过程来找到servlet的!

            ->   得到/hello字符串

     

            ->   使用/helloweb.xml文件中查找每一个<servlet-mapping>下的<url-pattern>标签里的内容,然后得到sevlet-name

     

            ->   使用sevlet-nameservlet标签中找到对应的相同名称的servlet配置。

     

            ->   得到servlet配置中的servlet-class内容。字符串:gz.itcast.a_servlet.HelloServlet

     

    复制代码
    <servlet>
        <servlet-name>HelloServlet</servlet-name> 
      <servlet-class>com.vmaxtam.numzero.addServlet</servlet-class>
    </servlet>

    <servlet-mapping>
      <servlet-name>HelloServlet</servlet-name>
       <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    复制代码

     

        最后通过反射实例化HelloServlet对象,然后调用HelloServlet中的方法。

     

     

    Servlet的映射路径

     

    <url-pattern>/hello</url-pattern> 这里的映射路径还可以用多种方式来填写!

                    url-pattern                           浏览器输入URL

    精确匹配                       /demo1                              http://localhost:8080/day10/demo1

                     /itcast/demo1          http://localhost:8080/day10/itcast/demo1  

     

    模糊匹配

                       /*                                 http://localhost:8080/day10/任意路径

                      /itcast/*                            http://localhost:8080/day10/itcast/任意路径

                      *.后缀名                        http://localhost:8080/day10/任意路径.后缀。例如 *.do,*.action, *.html

     

    注意: 

    1url-pattern要以/开头,要么以*开头。demo1这种写法是错误的!!

    2) /itcast/*.do 这种写法不合法。不能同时使用两种模糊匹配

    3)当一个请求有多个servlet被匹配的情况下:

    a)长的最像的url-pattern会优先被匹配

    b)以后缀名结尾的url-pattern优先级最低!!!

     

    说到这里,就有人问:这个只是在找Servlet文件,那么如果要找服务器的静态文件(html,xml等),服务器的执行过程如何??如果要找的文件不存在又会怎么样?

    下面为大家讲解:

     

     

    缺省路径

     

    tomcat服务器中有一个默认的Servlet,叫DefaultServlet,DefaultServlet的url-pattern为 。这个DefaultServlet的作用主要用于处理静态资源的请求。

     

        输入: http://localhost:8080/day10/test.html 如何找到资源呢?

     

            1)在day10web应用下查找web.xml文件,用/test.html,存在匹配是否存在符合规则url-pattern,找到就会执行对应的动态资源(servlet)。

     

            2)如果找不到对应的url-pattern,则到day10当前web应用的根目录下查找一个test.html名称的静态资源文件。如果找到这个文件,DefaultServlet读取该静态文件内容输出到浏览器客户端。

     

            3)如果在day10下找不到test.html的静态资源文件,那么返回404的页面。

     

    前面只说到服务器是如何找到Servlet这个文件,那么Servlet是如何执行的呢!!!这就是重点,Servlet的生命周期

     

    Servlet的生命周期

    tomcat服务器什么时候创建servlet对象?什么时候销毁对象?什么时候调用了什么方法?!

    其实也就是这样的一个过程 :   

          1.Servlet对象的创建。

          2.Servlet对象执行某些方法来给我们服务。

          3.Servlet对象的销毁。

     

    而这个过程有4个很核心的方法需要执行:

    构造方法: servlet对象创建时调用。默认情况下,第一次访问servlet时,servlet对象创建。只被调 用1次。servlettomcat服务器中是单实例的。

    init方法:  在创建完servlet对象之后被调用。用于对servlet对象进行初始化。只调用1次。

    service方法:每次发出请求时被调用。调用n次。

    destroy方法: 在tomcat服务器停止或者web应用重新加载时调用。只调用1次。

     

    下面我们用伪代码来演示一下 浏览器发出请求 到服务器作出相应 整个过程中Servlet的执行过程!

    浏览器输入: http://localhost:8080/day10/hello

     进入web.html查询资源。

    得到字符串 gz.itcast.a_servlet.HelloServlet

     

    模拟tomcat服务器内部的运行代码:

    1)用反射构造HelloServlet对象

      1.1 得到字节码对象

        Class clazz = Class.forName("gz.itcast.a_servlet.HelloServlet ")

      1.2 调用无参的构造方法构造对象

        Object obj = clazz.newInstance();       ----1.Servlet的构造方法被执行

    2)创建ServletConfig对象,调用init方法

         2.1 得到init方法对象

        Method method = clazz.getDeclareMethod("init",ServletConfig.class);

      2.2 执行init方法

        method.invoke(obj, config);               --2. Servletinit方法被执行

     

    3)创建requestresponse对象,调用service方法

      3.1 得到service方法对象

        Method m = clazz.getDeclareMethod("service",HttpServletRequest.class,HttpServletResponse.class);

      3.2 执行方法

        m.invoke(obj,request,response);          --3.Servletservice方法被执行

     

    4tomcat服务器停止或web应用重新加载时,调用destroy方法

      4.1 得到destroy方法对象

        Method method = clazz.getDeclareMethod("destroy",null);

       4.2 执行方法

        method.invoke(obj,null);               --4.Servletdestroy方法被执行

     

    如果文字不够直观,那么我看可以看一下流程图

    Servlet对象自动加载

    引入

        默认情况下,servlet对象会在第一次请求servlet时被创建。创建完之后调用init方法。假如构造方法或者init方法执行的业务逻辑比较多,那么用户在第一次访问servlet时的等待会变长,影响用户的体验。

    解决办法

        改变servlet的创建时机:让servlet对象在tomcat服务器启动web应用加载时创建。

     

    servlet的配置中,加入一个配置:

    <load-on-startup>正整数</load-on-startup>

     

    <servlet>

        <servlet-name>LifeDemo1</servlet-name>

        <servlet-class>gz.itcast.c_life.LifeDemo1</servlet-class>

        <load-on-startup>1</load-on-startup>

      </servlet>

    注意: 正整数的数值越大,创建的优先级就越低!!

     

     Servlet的多线程安全问题

        结论: servlettomcat服务器中是单实例多线程的.

     

    多线程并发问题

      多个线程之间同时操作了共享数据!!!

    解决多线程并发问题

      给需要同步的代码块加上唯一的对象锁。

     

    如何编写线程安全的servlet类:

      1)尽量不要使用成员变量。

      2)如果使用成员变量,要给用到了成员变量的代码块加上锁。尽量缩小同步代码块的范围,以避免因为同步导致执行效率问题。

     

    Init方法

      在GenericServlet中提供了一个无参数的init方法!!!

        有参数的init:该方法是Servlet的四个生命周期方法中的一个,该方法一定会被服务器调用。在该方法中会调用无参数的init方法。

        无参数的init:该方法是Sun公司设计出来方便开发者进行重写,在该方法中实现对servlet对象的初始化工作,这个方法会被有参的init方法调用!

     

    学习之所以会想睡觉,是因为那是梦开始的地方。
  • 相关阅读:
    redis 解析配置文件
    redis 五大数据类型之sortedset
    redis 五大数据类型之hash篇
    redis 五大数据类型之set篇
    redis 五大数据类型之list篇
    redis_key键
    redis 五大数据类型之string篇
    redis使用
    redis下载安装
    Neutron Kilo-Liberty-Mitaka各版本区别
  • 原文地址:https://www.cnblogs.com/holdon521/p/4123121.html
Copyright © 2020-2023  润新知