[Spring Framework]bean的生命周期以及控制

简介: bean的生命周期以及控制

@[TOC]

bean的生命周期控制(配置文件法)

bean的生命周期就是bean对象从创建到销毁的整体过程。

我们在bean的生命周期中可以干一些事情(也就是对他的生命周期进行一些控制),例如创建之后(比如用来初始化需要用到资源),销毁之前(比如用来释放用到的资源)。

接下来我们进行尝试:

首先项目背景:

有一个实现了BookDao接口的是实现类BookDaoImpl:

public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
}

我们把它放到IOC容器中:

<bean id="bookDao" name="bookBookDao" class="impl.BookDaoImpl"/>

接下来我们就以这个实现类BookDaoImpl为例子:

首先我们在实现类BookDaoImpl中编写两个方法,分别对应着初始化方法、销毁方法:

public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
    //表示bean初始化对应的操作
    public void init(){
        System.out.println("init...");
    }
    //表示bean销毁前对应的操作
    public void destory(){
        System.out.println("destory...");
    }
}
注意这两个方法不能有返回值,不要有参数!

然后我们在Spring的配置文件中对他们进行配置,是他们真正的成为生命周期的控制方法:

<bean id="bookDao" name="bookBookDao" class="impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
  • init-method来配置初始化方法
  • destroy-method来配置销毁方法

这样就完成了,接下来我们运行程序:

public class App3 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();
    }
}

结果为:
在这里插入图片描述

==我们发现销毁方法并没有执行,这是为什么呢?==

Spring的IOC容器是运行在JVM中,运行main方法后,JVM启动,Spring加载配置文件生成IOC容器,从容器获取bean对象,然后调方法执行,main方法执行完后,JVM退出,这个时候IOC容器中的bean还没有来得及销毁就已经结束了,所以没有调用对应的destroy方法。

容器的关闭

如果我们想要销毁方法生效,那么我们就要在jvm关闭之前就把IOC容器进行关闭,而这里关闭IOC容器有两种方式:

  • close关闭容器
  • 注册钩子关闭容器

首先我们说说如何使用close关闭容器。要想使用close方法,那么得先有close方法:
在这里插入图片描述
close方法是从ConfigurableApplicationContext接口之后才开始有的,也就是说如果你写成如下是调用不了close方法的:

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

如上是一个注意点,好在我们的代码是没有这种问题的:
在这里插入图片描述
然后调用close方法即可:

public class App3 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();
        ctx.close();

    }
}

结果:

在这里插入图片描述

然后我们再注册钩子关闭容器,

  • 在容器未关闭之前,提前设置好回调函数,让JVM在退出之前回调此函数来关闭容器
  • 调用ctx的registerShutdownHook()方法

    ctx.registerShutdownHook();
    注意:registerShutdownHook在ApplicationContext中也没有
public class App3 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();
//        ctx.close();
        ctx.registerShutdownHook();
    }
}

结果:
在这里插入图片描述

这两种关闭方法的区别在于:==close()是在调用的时候关闭,registerShutdownHook()是在JVM退出前调用关闭。==

bean的生命周期控制(实现接口法)

分析上面的实现过程,会发现添加初始化和销毁方法,即需要编码也需要配置,实现起来步骤比较多也比较乱。

Spring提供了两个接口来完成生命周期的控制,好处是可以不用再进行配置init-methoddestroy-method

我们接下来进行试验:

添加项目背景:

现在有一个实现了BookService接口的BookServiceImpl类,它依赖于BookDao:

public class BookServiceImpl implements BookService {
    private BookDao bookDao;

    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}

我们以他为例子,首先实现两个接口InitializingBeanDisposableBean并实现接口中的两个方法afterPropertiesSetdestroy

public class BookServiceImpl implements BookService, DisposableBean, InitializingBean {
    private BookDao bookDao;

    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    public void destroy() throws Exception {
        System.out.println("service destroy");
    }

    public void afterPropertiesSet() throws Exception {
        System.out.println("service init");
    }

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}

在配置文件中,我们可以不使用那两个配置项:

    <bean id="bookDao" name="bookBookDao" class="impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
    <bean id="bookService" class="impl.BookServiceImpl" scope="prototype">
        <property name="bookDao" ref="bookBookDao"></property>
    </bean>

执行结果:
在这里插入图片描述
还有一个注意点:

对于InitializingBean接口中的afterPropertiesSet方法,翻译过来为属性设置之后。对于BookServiceImpl来说,bookDao是它的一个属性。setBookDao方法是Spring的IOC容器为其注入属性的方法。setBookDao应该在afterPropertiesSet之前执行。==推广一下初始化方法会在类中属性设置之后执行。==

我们实验一下:

在setBookDao中添加一个打印语句:

public class BookServiceImpl implements BookService, DisposableBean, InitializingBean {
    private BookDao bookDao;

    public void setBookDao(BookDao bookDao) {
        System.out.println("set property....");
        this.bookDao = bookDao;
    }

    public void destroy() throws Exception {
        System.out.println("service destroy");
    }

    public void afterPropertiesSet() throws Exception {
        System.out.println("service init");
    }

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}

然后我们再执行,结果如下:
在这里插入图片描述

总结

(1)关于Spring中对bean生命周期控制提供了两种方式:

  • 在配置文件中的bean标签中添加init-methoddestroy-method属性
  • 类实现InitializingBeanDisposableBean接口,这种方式了解下即可。

(2)对于bean的生命周期控制在bean的整个生命周期中所处的位置如下:

  • 初始化容器

    • 1.创建对象(内存分配)
    • 2.执行构造方法
    • 3.执行属性注入(set操作)
    • ==4.执行bean初始化方法==
  • 使用bean

    • 1.执行业务操作
  • 关闭/销毁容器

    • ==1.执行bean销毁方法==

(3)关闭容器的两种方式:

  • ConfigurableApplicationContext是ApplicationContext的子类

    • close()方法
    • registerShutdownHook()方法
相关文章
|
13天前
|
缓存 Java Spring
实战指南:四种调整 Spring Bean 初始化顺序的方案
本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析: 1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。 2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。 3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。
实战指南:四种调整 Spring Bean 初始化顺序的方案
|
1月前
|
XML Java 数据格式
Spring从入门到入土(bean的一些子标签及注解的使用)
本文详细介绍了Spring框架中Bean的创建和使用,包括使用XML配置文件中的标签和注解来创建和管理Bean,以及如何通过构造器、Setter方法和属性注入来配置Bean。
67 9
Spring从入门到入土(bean的一些子标签及注解的使用)
|
1月前
|
Java 测试技术 Windows
咦!Spring容器里为什么没有我需要的Bean?
【10月更文挑战第11天】项目经理给小菜分配了一个紧急需求,小菜迅速搭建了一个SpringBoot项目并完成了开发。然而,启动测试时发现接口404,原因是控制器包不在默认扫描路径下。通过配置`@ComponentScan`的`basePackages`字段,解决了问题。总结:`@SpringBootApplication`默认只扫描当前包下的组件,需要扫描其他包时需配置`@ComponentScan`。
|
1月前
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细解析Spring Bean的生命周期及其核心概念,并深入源码分析。Spring Bean是Spring框架的核心,由容器管理其生命周期。从实例化到销毁,共经历十个阶段,包括属性赋值、接口回调、初始化及销毁等。通过剖析`BeanFactory`、`ApplicationContext`等关键接口与类,帮助你深入了解Spring Bean的管理机制。希望本文能助你更好地掌握Spring Bean生命周期。
77 1
|
1月前
|
Java Spring
获取spring工厂中bean对象的两种方式
获取spring工厂中bean对象的两种方式
39 1
|
1月前
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细介绍了Spring框架中的核心概念——Spring Bean的生命周期,包括实例化、属性赋值、接口回调、初始化、使用及销毁等10个阶段,并深入剖析了相关源码,如`BeanFactory`、`DefaultListableBeanFactory`和`BeanPostProcessor`等关键类与接口。通过理解这些核心组件,读者可以更好地掌握Spring Bean的管理和控制机制。
84 1
|
2月前
|
XML Java 数据格式
spring复习03,注解配置管理bean
Spring框架中使用注解配置管理bean的方法,包括常用注解的标识组件、扫描组件、基于注解的自动装配以及使用注解后的注意事项,并提供了一个基于注解自动装配的完整示例。
spring复习03,注解配置管理bean
|
5月前
|
Java 开发者 Spring
解析Spring中Bean的生命周期
解析Spring中Bean的生命周期
55 2
|
5月前
|
XML druid Java
Spring5系列学习文章分享---第二篇(IOC的bean管理factory+Bean作用域与生命周期+自动装配+基于注解管理+外部属性管理之druid)
Spring5系列学习文章分享---第二篇(IOC的bean管理factory+Bean作用域与生命周期+自动装配+基于注解管理+外部属性管理之druid)
62 0
|
4月前
|
Java Spring 容器
Spring Boot 启动源码解析结合Spring Bean生命周期分析
Spring Boot 启动源码解析结合Spring Bean生命周期分析
103 11