【Spring】bean的生命周期


这里写目录标题

  • [1. 在类中提供生命周期控制方法,并在配置文件中配置init-method&destroy-method(配置)](#1. 在类中提供生命周期控制方法,并在配置文件中配置init-method&destroy-method(配置))
  • [2. 实现接口来做和init和destroy(接口)](#2. 实现接口来做和init和destroy(接口))
  • [3. bean的生命周期](#3. bean的生命周期)
  • [4. bean的销毁时机](#4. bean的销毁时机)

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

定义实现类如下:

java 复制代码
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...");
    }
}

配置方法如下:

xml 复制代码
<bean id="bookDaoCycle" class="com.example.demo231116.dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy" />

最终调用跟平时一样:

java 复制代码
// IoC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

BookDao bookDao5 = (BookDao) ctx.getBean("bookDaoCycle");
System.out.println(bookDao5);

输出结果为:

bash 复制代码
book dao init...
com.example.demo231116.dao.impl.BookDaoImpl@5dd6264

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

并没有自动调用destroy方法,因为在程序执行结束后,java虚拟机关闭,程序不会自动调用destroy方法,如果需要调用,可以在程序的末尾加上:ctx.close(),即在java虚拟机关闭之前执行destroy方法

但是事实上,ApplicationContext 并没有close方法, ApplicationContext 下的一个接口才有定义close方法,所以这里想要使用close方法,可以修改IoC容器定义:ClassPathXmlApplicationContextctx = new ClassPathXmlApplicationContext("applicationContext.xml");

然后再末尾调用ctx.close():

java 复制代码
// IoC容器
ClassPathXmlApplicationContextctx = new ClassPathXmlApplicationContext("applicationContext.xml");

BookDao bookDao5 = (BookDao) ctx.getBean("bookDaoCycle");
System.out.println(bookDao5);

ctx.close()

输出结果为:

bash 复制代码
book dao init...
com.example.demo231116.dao.impl.BookDaoImpl@5dd6264
book dao destroy...

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

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

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

java 复制代码
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ctx.registerShutdownHook();

BookDao bookDao5 = (BookDao) ctx.getBean("bookDaoCycle");
System.out.println(bookDao5);

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

java 复制代码
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();
    }
}

得到的结果是这样的:

bash 复制代码
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...

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

如果我不使用单例而是定义多例的scope:

xml 复制代码
<bean id="bookDaoCycle" class="com.example.demo231116.dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy" scope="prototype" />

主代码如下:

java 复制代码
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();
    }
}

这样运行的结果是:

bash 复制代码
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

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

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

只需要在bean类下多实现这两个接口:

并继承必要的方法:

定义代码如下:

java 复制代码
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");
    }
}

Spring Config配置如下:

xml 复制代码
<bean id="bookDaoCycle" class="com.example.demo231116.dao.impl.BookDaoImpl" />

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

3. bean的生命周期

4. bean的销毁时机

相关推荐
卷无止境42 分钟前
写代码这件事,到底该讲究点什么?
后端·python
卷无止境1 小时前
循环复杂度到底在算什么,Python 代码怎么才能写得让人一看就懂
后端·python
lpfasd1231 小时前
MediaCrawler 项目深度分析
chrome·python·chrome devtools
Dxy12393102161 小时前
Python项目打包成EXE完整教程(PyInstaller实战避坑)
开发语言·python
bamb002 小时前
一个项目带你入门AI应用开发01
python
0566462 小时前
Python康复训练——常用标准库
开发语言·python·学习
极光代码工作室2 小时前
基于SpringBoot的课程预约系统
java·springboot·web开发·后端开发
昆曲之源_娄江河畔2 小时前
Python如何安装flask, pymssql
开发语言·python·flask·pymssql
Leighteen3 小时前
`try-finally` 里的 `return`:为什么 `finally` 会悄悄改掉返回值、吞掉异常
java·开发语言
0566463 小时前
Python康复训练——控制流与函数
开发语言·python·学习