【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的销毁时机

相关推荐
程序员清风几秒前
阿里二面:Kafka 消费者消费消息慢(10 多分钟),会对 Kafka 有什么影响?
java·后端·面试
幼稚园的山代王几秒前
Prompt Enginering(提示工程)先进技术
java·人工智能·ai·chatgpt·langchain·prompt
周某某~10 分钟前
二.单例模式‌
java·单例模式·设计模式
摸鱼仙人~12 分钟前
深入理解Java单例模式:确保类只有一个实例
java·javascript·单例模式
nenchoumi311926 分钟前
AirSim/Cosys-AirSim 游戏开发(一)XBox 手柄 Windows + python 连接与读取
windows·python·xbox
GoodStudyAndDayDayUp27 分钟前
初入 python Django 框架总结
数据库·python·django
hstar952728 分钟前
三十五、面向对象底层逻辑-Spring MVC中AbstractXlsxStreamingView的设计
java·后端·spring·设计模式·架构·mvc
星辰大海的精灵35 分钟前
基于Dify+MCP实现通过微信发送天气信息给好友
人工智能·后端·python
精灵vector40 分钟前
Agent短期记忆的几种持久化存储方式
人工智能·python
pengyu1 小时前
【Java设计原则与模式之系统化精讲:壹】 | 编程世界的道与术(实战指导篇)
java·后端·设计模式