[Spring实战系列](10)初探Bean生命周期

简介: 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SunnyYoona/article/details/50636097 1. 生命周期流程图Bean在Spring容器中从创建到销毁经历了若干个阶段,在每一个阶段都可以针对Spring如何管理Bean进行个性化定制。
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SunnyYoona/article/details/50636097
1. 生命周期流程图


Bean在Spring容器中从创建到销毁经历了若干个阶段,在每一个阶段都可以针对Spring如何管理Bean进行个性化定制。

正如你所见,在Bean 准备就绪之前,Bean 工厂执行了若干启动步骤。

  • Spring 对Bean 进行实例化
  • Spring 将值和Bean 的引用注入进Bean 对应的属性中。
  • 如果Bean 实现了BeanNameAware接口,Spring 将Bean的ID传递给setBeanName() 接口方法
  • 如果Bean 实现了BeanFactoryAware接口,Spring 将调用setBeanFactory()接口方法,将BeanFactory 容器实例传入。
  • 如果Bean 实现了ApplicationContextAware 接口,Spring 将调用setApplicationContext()接口方法,将应用上下文的引用传入。
  • 如果Bean 实现了BeanPostProcessor 接口,Spring 将调用它们的postProcessBeforeInitialization() 接口方法
  • 如果Bean 实现了InitializingBean 接口,Spring 将调用它们的afterPropertiesSet() 接口方法。类似地,如果Bean 使用init-method 声明了初始化方法,该方法也会被调用。
  • 如果Bean 实现了BeanPostProcessor 接口,Spring 将调用它们的postPoressAfterInitialization() 接口方法
  • 此时此刻,Bean 已经准备就绪,可以被应用程序使用了,它们将一直驻留在应用上下文中,直到该应用上下文被销毁。
  • 如果Bean 实现了DisposableBean 接口,Spring 将调用它的destroy()接口方法。同样,如果Bean 使用destroy-method 声明了销毁方法,该方法也会被调用。

2. 各种接口方法分类
 
Bean的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类:
方法 用途
Bean自身的方法 这个包括了Bean本身调用的方法和通过配置文件中<bean>的init-method和destroy-method指定的方法
Bean级生命周期接口方法 这个包括了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这些接口的方法
容器级生命周期接口方法 这个包括了InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“后处理器”。
工厂后处理器接口方法 这个包括了AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer等等非常有用的工厂后处理器接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。
   
3. 实例

我们用一个简单的Spring Bean来演示一下Spring Bean的生命周期。
 
首先是一个简单的Spring Bean,它实现了BeanNameAware,BeanFactoryAware,InitializingBean,ApplicationContextAware和DiposableBean这5个接口,同时有2个方法(myInit()方法和myDestroy方法),对应配置文件中<bean>的init-method和destroy-method。

 
   
package com.sjf.bean;
 
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
 
/**
* Student实体类
* @author sjf0115
*
*/
public class Student implements BeanNameAware,BeanFactoryAware,InitializingBean,ApplicationContextAware, DisposableBean{
private String name;
private int age;
private String school;
// 构造器
public Student(){
System.out.println("constructor Student...");
}
public void setName(String name) {
this.name = name;
System.out.println("setName...");
}
 
public void setAge(int age) {
this.age = age;
System.out.println("setAge...");
}
 
public void setSchool(String school) {
this.school = school;
System.out.println("setSchool...");
}
 
public void myInit(){
System.out.println("init-method...");
}
public void myDestroy(){
System.out.println("destroy-method...");
}
// 来自于BeanNameAware接口
public void setBeanName(String arg0) {
System.out.println("setBeanName...[" + arg0 + "]");
}
// 来自于BeanFactoryAware接口
public void setBeanFactory(BeanFactory arg0) throws BeansException {
System.out.println("setBeanFactory...");
}
// 来自于InitializingBean
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet...");
}
// 来自于DisposableBean
public void destroy() throws Exception {
System.out.println("destroy...");
}
// 来自于ApplicationContextAware接口
public void setApplicationContext(ApplicationContext arg0) throws BeansException {
System.out.println("setApplicationContext...");
}
@Override
public String toString() {
return "name:" + name + " age:" + age + " school:" + school;
}
}

然后是自定义一个MyBeanPostProcessor Bean,实现了 BeanPostProcessor接口。
 
   
package com.sjf.bean;
 
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
 
/**
* 自定义BeanPostProcessor
* @author sjf0115
*
*/
public class MyBeanPostProcessor implements BeanPostProcessor{
public MyBeanPostProcessor(){
System.out.println("constructor MyBeanPostProcessor...");
}
// 来自于BeanPostProcessor接口
public Object postProcessAfterInitialization(Object arg0, String arg1) throws BeansException {
System.out.println("postProcessAfterInitialization...[" + arg1 + "]");
return arg0;
}
// 来自于BeanPostProcessor接口
public Object postProcessBeforeInitialization(Object arg0, String arg1) throws BeansException {
System.out.println("postProcessBeforeInitialization...[" + arg1 + "]");
return arg0;
}
}

BeanPostProcessor接口包括2个方法postProcessAfterInitialization()和postProcessBeforeInitialization(),这两个方法的第一个参数都是要处理的Bean对象,第二个参数都是Bean的name。返回值也都是要处理的Bean对象。

接口中的两个方法都要将传入的bean返回,而不能返回null,如果返回的是null那么我们通过getBean方法将得不到目标。

一般ApplicationContext会自动检查是否在定义文件中有实现了BeanPostProcessor接口的类,如果有的话,Spring容器会在每个Bean(其他的Bean)被初始化之前和初始化之后,分别调用实现了BeanPostProcessor接口的类的postProcessAfterInitialization()方法和postProcessBeforeInitialization()方法,对Bean进行相关操作。刚开始 只定义了 Student 一个bean,并且实现了BeanPostProcessor接口,并不会调用 postProcessAfterInitialization()和postProcessBeforeInitialization()方法,这时ApplicationContext找不到 实现了BeanPostProcessor接口的类。 所以这里一个 Bean用来实现BeanPostProcessor接口,然后另一个Bean用来配合实现了BeanPostProcessor接口的Bean。

网友的疑问以及解答: http://bbs.csdn.net/topics/300121037

配置文件applicationContext.xml:

 
   
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id = "yoona" class = "com.sjf.bean.Student" scope="singleton" init-method="myInit" destroy-method="myDestroy">
<property name="name" value="yoona"/>
<property name="age" value="24"/>
<property name="school" value="西电"/>
</bean>
<bean id = "myBeanPostProcessor" class="com.sjf.bean.MyBeanPostProcessor"/>
</beans>

测试代码:

 
   
package com.sjf.bean;
 
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
 
/**
* 测试类
* @author sjf0115
*
*/
public class Test {
 
private static ApplicationContext context;
private static Student stu;
public static void main(String[] args) {
context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 2. 从IOC容器中获取Bean实例
stu = (Student)context.getBean("yoona");
// 3.调用listAllBook方法
System.out.println(stu.toString());
// 4.关闭容器
((ClassPathXmlApplicationContext) context).registerShutdownHook();
}
}

运行结果:
 
   
constructor MyBeanPostProcessor...
constructor Student...
setName...
setAge...
setSchool...
setBeanName...[yoona]
setBeanFactory...
setApplicationContext...
postProcessBeforeInitialization...[yoona]
afterPropertiesSet...
init-method...
postProcessAfterInitialization...[yoona]
nameyoona age24 school:西电
destroy...
destroy-method...
从这个运行结果中我们就可以看出一个Bean的生命周期:constructor( 实例化) -> setXXX( 填充属性) -> BeanName( BeanNameAware接口) -> BeanFactory( BeanFactoryAware接口) -> ApplicationContext( ApplicationContextAware接口 ) -> postProcessBeforeInitialization(BeanPostProcessor接口) -> afterPropertiesSet( InitializingBean接口 ) -> init-method(定制的初始化方法) -> postProcessAfterInitialization BeanPostProcessor接口  -> destroy( DisposableBean接口 ) -> destroy-method(定制的销毁方法


来源于:《Spring实战》


目录
相关文章
|
15天前
|
缓存 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。
70 9
Spring从入门到入土(bean的一些子标签及注解的使用)
|
29天前
|
自然语言处理 Java API
Spring Boot 接入大模型实战:通义千问赋能智能应用快速构建
【10月更文挑战第23天】在人工智能(AI)技术飞速发展的今天,大模型如通义千问(阿里云推出的生成式对话引擎)等已成为推动智能应用创新的重要力量。然而,对于许多开发者而言,如何高效、便捷地接入这些大模型并构建出功能丰富的智能应用仍是一个挑战。
109 6
|
1月前
|
缓存 NoSQL Java
Spring Boot与Redis:整合与实战
【10月更文挑战第15天】本文介绍了如何在Spring Boot项目中整合Redis,通过一个电商商品推荐系统的案例,详细展示了从添加依赖、配置连接信息到创建配置类的具体步骤。实战部分演示了如何利用Redis缓存提高系统响应速度,减少数据库访问压力,从而提升用户体验。
74 2
|
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生命周期。
83 1
|
1月前
|
Java Spring
获取spring工厂中bean对象的两种方式
获取spring工厂中bean对象的两种方式
40 1
|
1月前
|
Java 数据库连接 Spring
【2021Spring编程实战笔记】Spring开发分享~(下)
【2021Spring编程实战笔记】Spring开发分享~(下)
26 1
|
1月前
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细介绍了Spring框架中的核心概念——Spring Bean的生命周期,包括实例化、属性赋值、接口回调、初始化、使用及销毁等10个阶段,并深入剖析了相关源码,如`BeanFactory`、`DefaultListableBeanFactory`和`BeanPostProcessor`等关键类与接口。通过理解这些核心组件,读者可以更好地掌握Spring Bean的管理和控制机制。
87 1
|
1月前
|
XML Java 数据格式
Spring IOC容器的深度解析及实战应用
【10月更文挑战第14天】在软件工程中,随着系统规模的扩大,对象间的依赖关系变得越来越复杂,这导致了系统的高耦合度,增加了开发和维护的难度。为解决这一问题,Michael Mattson在1996年提出了IOC(Inversion of Control,控制反转)理论,旨在降低对象间的耦合度,提高系统的灵活性和可维护性。Spring框架正是基于这一理论,通过IOC容器实现了对象间的依赖注入和生命周期管理。
67 0
下一篇
无影云桌面