• 【Spring】bean的生命周期


    在这里插入图片描述
    在这里插入图片描述

    1. 在类中提供生命周期控制方法,并在配置文件中配置init-method&destroy-method(配置)

    定义实现类如下:

    package com.example.demo231116.dao.impl;
    
    import com.example.demo231116.dao.BookDao;
    
    public class BookDaoImpl implements BookDao {
        public void save(){
            System.out.println("book dao save...");
        }
    
        public void init(){
            System.out.println("book dao init...");
        }
    
        public void destroy(){
            System.out.println("book dao destroy...");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    配置方法如下:

    <bean id="bookDaoCycle" class="com.example.demo231116.dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy" />
    
    • 1

    最终调用跟平时一样:

    // IoC容器
    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    
    BookDao bookDao5 = (BookDao) ctx.getBean("bookDaoCycle");
    System.out.println(bookDao5);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    输出结果为:

    book dao init...
    com.example.demo231116.dao.impl.BookDaoImpl@5dd6264
    
    • 1
    • 2

    关闭容器操作1:ctx.close()

    并没有自动调用destroy方法,因为在程序执行结束后,java虚拟机关闭,程序不会自动调用destroy方法,如果需要调用,可以在程序的末尾加上:ctx.close(),即在java虚拟机关闭之前执行destroy方法
    但是事实上,ApplicationContext 并没有close方法, ApplicationContext 下的一个接口才有定义close方法,所以这里想要使用close方法,可以修改IoC容器定义:ClassPathXmlApplicationContextctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    然后再末尾调用ctx.close():

    // IoC容器
    ClassPathXmlApplicationContextctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    
    BookDao bookDao5 = (BookDao) ctx.getBean("bookDaoCycle");
    System.out.println(bookDao5);
    
    ctx.close()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    输出结果为:

    book dao init...
    com.example.demo231116.dao.impl.BookDaoImpl@5dd6264
    book dao destroy...
    
    • 1
    • 2
    • 3

    但是如果是这样的话,ctx.close()只能在程序的末尾写,因为在开头定义结束就写的话,这个IoC容器就被销毁了,下面也不可能执行一些getBean的操作

    关闭容器操作2:关闭钩子:ctx.registerShutdownHook()

    我们可以注册一个关闭钩子,在不用强行关闭IoC容器的情况下,设置在java虚拟机关闭之前让程序执行销毁的方法:

    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    ctx.registerShutdownHook();
    
    BookDao bookDao5 = (BookDao) ctx.getBean("bookDaoCycle");
    System.out.println(bookDao5);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这样就不再需要强硬地执行ctx.close()方法了
    :我在写这些代码的过程中发现一个老师没有提及的点,也是我之前一直忽略的,这些init方法的执行,是在初始化IoC容器时候就执行了,我的完整代码如下:

    package com.example.demo231116;
    
    import com.example.demo231116.dao.BookDao;
    import com.example.demo231116.service.BookService;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class Demo231116Application2 {
        public static void main(String[] args) {
            // 3. 获取IoC容器
            ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
            ctx.registerShutdownHook();
            // 4. 获取bean
    //        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
    //        bookDao.save();
            BookService bookService = (BookService) ctx.getBean("bookService");
            bookService.save();
    
            BookDao bookDao = (BookDao) ctx.getBean("dao");
            BookDao bookDao1 = (BookDao) ctx.getBean("dao");
            System.out.println(bookDao);
            System.out.println(bookDao1);
    
            BookDao bookDao2 = (BookDao) ctx.getBean("bookDaoFactory");
            System.out.println(bookDao2);
    
            BookDao bookDao3 = (BookDao) ctx.getBean("bd");
            System.out.println(bookDao3);
    
            BookDao bookDao4 = (BookDao) ctx.getBean("bookDaoFactoryMethod");
            System.out.println(bookDao4);
    
            BookDao bookDao5 = (BookDao) ctx.getBean("bookDaoCycle");
            System.out.println(bookDao5);
    
    //        ctx.close();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    得到的结果是这样的:

    Factory method....
    实例工厂方法...
    book dao init...
    book service save...
    book dao save...
    com.example.demo231116.dao.impl.BookDaoImpl@6193932a
    com.example.demo231116.dao.impl.BookDaoImpl@6193932a
    com.example.demo231116.dao.impl.BookDaoImpl@647fd8ce
    com.example.demo231116.dao.impl.BookDaoImpl@159f197
    com.example.demo231116.dao.impl.BookDaoImpl@78aab498
    com.example.demo231116.dao.impl.BookDaoImpl@5dd6264
    book dao destroy...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    事实上,init方法是在IoC容器初始化的时候执行了,而不是在我具体调用getBean()的时候才运行的,默认bean是单例模式,一开始就把init()给执行掉了
    如果我不使用单例而是定义多例的scope:

    <bean id="bookDaoCycle" class="com.example.demo231116.dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy" scope="prototype" />
    
    • 1

    主代码如下:

    package com.example.demo231116;
    
    import com.example.demo231116.dao.BookDao;
    import com.example.demo231116.service.BookService;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class Demo231116Application2 {
        public static void main(String[] args) {
            // 3. 获取IoC容器
            ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
            ctx.registerShutdownHook();
            // 4. 获取bean
    //        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
    //        bookDao.save();
            BookService bookService = (BookService) ctx.getBean("bookService");
            bookService.save();
    
            BookDao bookDao = (BookDao) ctx.getBean("dao");
            BookDao bookDao1 = (BookDao) ctx.getBean("dao");
            System.out.println(bookDao);
            System.out.println(bookDao1);
    
            BookDao bookDao2 = (BookDao) ctx.getBean("bookDaoFactory");
            System.out.println(bookDao2);
    
            BookDao bookDao3 = (BookDao) ctx.getBean("bd");
            System.out.println(bookDao3);
    
            BookDao bookDao4 = (BookDao) ctx.getBean("bookDaoFactoryMethod");
            System.out.println(bookDao4);
    
            BookDao bookDao5 = (BookDao) ctx.getBean("bookDaoCycle");
            BookDao bookDao6 = (BookDao) ctx.getBean("bookDaoCycle");
            System.out.println(bookDao5);
            System.out.println(bookDao6);
    
    //        ctx.close();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    这样运行的结果是:

    Factory method....
    实例工厂方法...
    book service save...
    book dao save...
    com.example.demo231116.dao.impl.BookDaoImpl@d4342c2
    com.example.demo231116.dao.impl.BookDaoImpl@d4342c2
    com.example.demo231116.dao.impl.BookDaoImpl@2bbf180e
    com.example.demo231116.dao.impl.BookDaoImpl@163e4e87
    com.example.demo231116.dao.impl.BookDaoImpl@56de5251
    book dao init...
    book dao init...
    com.example.demo231116.dao.impl.BookDaoImpl@78aab498
    com.example.demo231116.dao.impl.BookDaoImpl@5dd6264
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    是在具体定义实例的时候才执行的init方法,所以scope不同,init方法执行的先后顺序是不一样的

    2. 实现接口来做和init和destroy(接口)

    只需要在bean类下多实现这两个接口:
    并继承必要的方法:
    在这里插入图片描述
    定义代码如下:

    package com.example.demo231116.dao.impl;
    
    import com.example.demo231116.dao.BookDao;
    import org.springframework.beans.factory.DisposableBean;
    import org.springframework.beans.factory.InitializingBean;
    
    public class BookDaoImpl implements BookDao, InitializingBean, DisposableBean {
        public void save(){
            System.out.println("book dao save...");
        }
    
    //    public void init(){
    //        System.out.println("book dao init...");
    //    }
    
        @Override
        public void destroy() throws Exception {
            System.out.println("接口destroy");
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("接口init");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    Spring Config配置如下:

    <bean id="bookDaoCycle" class="com.example.demo231116.dao.impl.BookDaoImpl" />
    
    • 1

    这个afterPropertiesSet的init方法,是在先执行属性设置后再执行init方法

    3. bean的生命周期

    在这里插入图片描述

    4. bean的销毁时机

    在这里插入图片描述

  • 相关阅读:
    【力扣刷题练习】42. 接雨水
    全栈开发之基于云开发实现微信聊天功能
    SSM+图书馆电子文件资源管理 毕业设计-附源码191614
    qt 读取txt文本内容时,中文乱码
    java常见锁策略与CAS
    codeforces (C++ Haunted House)
    11. 第一章总结
    Python 全栈系列187 分片(分区)规则
    俄罗斯考虑购买700亿美元的“友好”国家外汇
    Tomcat 源码分析 (设计模式) (七)
  • 原文地址:https://blog.csdn.net/passer__jw767/article/details/134452302