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

相关推荐
就这个java爽!1 分钟前
JAVA网络编程【基于TCP和UDP协议】超详细!!!
java·开发语言·网络·tcp/ip·udp·eclipse·idea
hzw05102 分钟前
Jupyter的使用
ide·python·jupyter
一叶飘零_sweeeet5 分钟前
为什么 Feign 要用 HTTP 而不是 RPC?
java·网络协议·http·spring cloud·rpc·feign
懒洋洋大魔王26 分钟前
7.Java高级编程 多线程
java·开发语言·jvm
茶馆大橘30 分钟前
【黑马点评】已解决java.lang.NullPointerException异常
java·开发语言
星辰@Sea34 分钟前
服务注册中心对比及使用场景分析
java·云原生
马剑威(威哥爱编程)37 分钟前
除了递归算法,要如何优化实现文件搜索功能
java·开发语言·算法·递归算法·威哥爱编程·memoization
bug菌¹39 分钟前
滚雪球学SpringCloud[4.1讲]: Spring Cloud Gateway详解
java·spring cloud·微服务
bug菌¹43 分钟前
滚雪球学SpringCloud[4.2讲]: Zuul:Netflix API Gateway详解
spring·spring cloud·gateway
小哇6661 小时前
spring-TransactionTemplate 编程式事务
数据库·spring