Servlet声明周期 [JavaWeb][Servlet]

Servlet生命周期

这里的Servlet表示一个Servlet对象, 而对象的生命周期就是指一个对象从被创建到被销毁的整个过程
Servlet运行在Servlet容器(web服务器)中, 其生命周期由Servlet容器(web服务器)来管理, 分为4个阶段:(如下)
  1. 加载和实例化:

    • 默认情况下, Servlet第一次被访问时, 由web容器(web服务器)创建Servlet对象

      • 默认情况之下Servlet第一次被访问的时候由容器创建Servlet对象, 那么说明不默认的情况之下, 我们其实可以设置为在web服务器启动时创建Servlet对象, 那么如何设置为这种不默认的情况(也就是如何设置为在web服务器启动的时候创建Servlet对象?)

        • 我们可以通过@WebServlet注解中的一个配置参数(成员变量)loadOnStartup来设置web服务器创建Servlet对象的时机

        • eg:

          @WebServlet(urlPatterns = "/demo",loadOnStartup = 1)
          
          • 当loadOnStartup值为负整数时,表示在第一次被访问时创建Servlet对象
          • 当loadOnStartup值为0或者正整数的时候,表示在服务器启动的时候创建Servlet对象
            • 也就是loadOnStartup的值为非负整数的时候就是表示是在启动服务器的时候创建Servlet对象
          • 数字越小优先级越高
    • loadOnStartup的值默认为-1(负一)

  • 我们在启动Web服务器的时候就创建Servlet对象的好处就是将我们的Servlet对象的创建时间划分到了Web容器启动的过程中, 如果我们是在第一次Servlet访问的时候创建Servlet对象那么可能会导致Servlet第一次被访问的时候响应比较慢 —> 因为相当于我们的Servlet类第一次被访问的时候我们要创建Servlet对象,还要初始化Servlet对象,然后还要做出服务(回应),也就是会调用三个方法,会比较慢

    * 所以我们就可以将我们的Servlet对象的创建时机修改为在服务器启动的时候就创建
    
这里我们可以通过Servlet是单例类的概念来记忆我们的Servlet创建的时机, 因为单例类无非就是懒汉式和饿汉式, 饿汉式就是一上来就创建, 也就是在服务器刚刚启动的时候就创建, 而懒汉式就是只有等到需要的时候最后才会创建, 也就是Servlet被访问了, 这个时候必须要使用了, 才创建
  1. 初始化:

    • 在Servlet实例化之后, 容器将调用Servlet的init()方法初始化这个Servlet对象, 完成一些如: 加载配置文件, 创建连接等初始化操作
      • 该方法只调用一次
  2. 请求处理:

    • 每次请求Servlet时,Servlet容器都会调用Servlet对象的service()方法对请求进行处理
      • 该方法每次请求都会执行, 所以如果有多次请求那么这个方法就会执行多次
  3. 服务终止

    • 当要释放内存或者web容器(web服务器)关闭时,web容器(web服务器)就会调用Servlet实例的destroy()方法完成资源的释放, 在destroy()方法调用之后,容器会释放这个Servlet实例
      • 该Servlet类的实例随后会被Java立即收集器所回收
      • 该方法执行一次
注意: 我们初始化状态的时候执行的init()方法和服务终止的时候执行的destroy()方法只是提供给程序员的一个时机而已, 就和我们的finalized()方法一样, 只是提供了一个时机, 会在某种时机调用对应的方法, 如果我们需要在这些时机去做一些事情, 那么我们就可以将对应的操作写到对应的方法中即可
  • 所以也就是并不是说我们的init()方法就是用来执行服务器的初始化操作的, 不是的, 我们的init()方法只是一个时机, 只是会在服务器初始化的时候被调用而已, 同样的, 我们的destroy()方法也不是服务器用来销毁资源的, 只是服务器销毁资源的时候会调用此方法而已
代码示例:
@WebServlet("/demo")
public class ServletDemo2 implements Servlet{
    /*
    初始化方法:
       1. 调用时机: 默认情况之下,Servlet被第一次访问时调用
       2. 调用次数: 一次
    */
    public void init(ServletConfig coifig){
        System.out.println("初始化~~")
    }
    
    /*
    提供服务的方法
       1. 调用时机: 每一次Servlet被访问时调用
       2. 调用次数: 每次
    */
    public void service(ServletRequest req,ServletResponse resp){
        System.out.println("提供服务~~");
    }
    
    /*
    销毁方法
       1. 调用时机: 内存释放或者服务器关闭的时候, Servlet对象就要被销毁, 而销毁Servlet对象就要调用此方法
       2. 调用次数: 一次
    */
    public void destroy(){
        System.out.println("销毁Servlet对象~~");
    }
}
这里我们可以通过将我们上面的@WebServlet注解中的loadOnStartup属性设置为正整数或者0来让我们的Servlet类的对象是在启动Web服务器的时候就创建:(如下:)
@WebServlet(urlPatterns = "/demo2", loadOnStartup = 1)
  • 这个时候我们可以发现我们前面当只给@WebServlet的urlPatterns属性赋值的时候我们可以省略urlPatterns = , 这个是为什么?

    • 这个其实是因为在WebServlet注解中定义了一个value成员变量, 而value配置参数的作用和urlPatterns是完全一样的, 这个时候我们如果当只给一个配置参数赋值的时候直接就给value赋值即可, 我们之前讲过: 当我们的给注解中的成员变量赋值的时候如果我们只是给注解中的一个成员变量赋值, 那么此时我们如果这个成员变量名还是value,那么我们就可以省略这个value = , 也就是我们直接写值就可以了

      • 但是如果是我们要给两个成员属性赋值的时候我们这个时候就不能省略value了, 此时我们可以写为以下的两种形式:

        1. @WebServlet(value = "/demo2", loadOnStartup = 1)
          
        2. @WebServlet(urlPatterns = "/demo2", loadOnStartup = 1)
          
          • 我们为了见名知意肯定是会选择使用第二种形式

补充:

Servlet中的init()方法和destroy()方法都只是Java官方为我们提供的一个时机而已

  • init()方法中就是让我们执行一些初始化的操作, 我们的init()方法会在我们创建完成Servlet对象之后就立刻进行调用, 所以Servlet中的init()方法其实就是在刚刚创建完Servlet对象之后, 在服务器还没有被客户端访问之前提供的一个时机, 如果我们需要在这个时机中执行一些对应的操作, 我们就可以将这些操作写到我们的init()方法中
    • 比如: 如果我们是要建立一些链接的时候, 或者是我们要加载一些配置文件的时候我们就可以将这些对应的操作放到我们的init()方法中来执行
  • destroy()方法就是Java官方为程序员提供的一个我们的Servlet销毁前的一个时机, 如果我们需要在服务器关闭之前要执行某些操作的时候我们就可以将这些操作放到destroy()方法中执行
    • 比如: 如果我们需要在关闭服务器之前打印日志信息的时候, 这个时候我们就可以将打印日志的操作放到destroy()方法中执行

Servlet对象不由我们创建, 是由tomcat服务器创建的, 创建分为两种情况:

  1. 默认情况: 在第一次访问的时候对应的Servlet对象会被创建

  2. 在服务器启动的时候Servlet对象会被创建

    • 我们要通过在web.xml文件中配置如下:

    • <load-on-startup>1</load-on-startup>
      
      • 如果配置的load-on-startup标签中的标签体内容的值为非负数的时候就是表示在启动tomcat服务器的时候创建对应的Servlet对象
      • 如果配置的load-on-startup标签中的标签体内容的值为负数的时候就表示在对应的Servlet被访问的时候创建对应的Servlet对象
        • 默认值就是为负数 : 也就是在对应的Servlet被访问的时候创建Servlet对象

每个Servlet类只会创建一个对象, 并且对象是由tomcat服务器创建的

  • 所以我们可以发现Servlet类是一个单例类, 所以其实两种Servlet创建方式时机, 一种是懒汉式, 一种是饿汉式
    • 如果只有到了对应的Servlet类被访问的时候才创建Servlet类的对象的方式就是一种懒汉式的单例创建方式
    • 如果是启动tomcat服务器之后Servlet类立刻就会被创建的方式就是一种饿汉式的单例创建方式
      • 一上来就等不及, 立刻创建我们就称之为饿汉式
      • 如果只有到了必须要创建的时候才创建的我们就称之为懒汉式

在Servlet创建成功之后, 也就是调用完构造方法之后, 会立刻调用init()方法来实现一些初始化操作

  • 如果我们在我们的Servlet类中重写了init()方法, 那么就会调用我们本类的init()方法, 如果我们的Servlet类中没有重写init()方法, 那么就会调用GenericServlet类实现的init()方法

    • GenericServlet抽象类在实现Servlet接口的时候重写并实现了Servlet接口中继承下来的init()方法, 和destroy()方法, 但是注意: 虽然HttpServlet抽象类又继承了GenericServlet抽象类, 但是并没有去重复的实现init()方法和destroy()方法, 因为这种方法其实就是我们提供给程序员的一种时机, 我们并不会去具体的实现方法体, 我们即使是实现了之后也只是仅仅的实现, 实现的方法中的方法体其实还是空的, 就像我们的finalize()方法一样, 都是提供给程序员的一个时机, 我们主要是要程序员去重写这个方法并实现
      • 我们对于这种接口之下的抽象类中我们都是会实现对应的抽象方法, 但是实现之后方法体还是为空的 , 我们只是为了给程序员提供一种适配器的方式, 让我们的程序员编程的时候直接继承我们对应的抽象类即可, 编程就比较灵活, 想实现哪个方法就实现哪个方法, 如果是直接实现接口的方式, 那么我们就必须要将接口中所有的抽象方法全部都实现, 会很死板, 可能我们实际编程中并不会需要我们实现所有的方法
        • 所以我们一般都是接口指定一个规范, 然后接口下面就会有对应的抽象类, 抽象类可能有好多层, 也就是不断地从抽象变为具体
          • 我们一般都是在接口下面的第一个实现了接口的抽象类中实现接口中的抽象方法(但是仅仅是一个实现, 方法体一般都是为空的)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值