前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Spring Bean生命周期总结「建议收藏」

Spring Bean生命周期总结「建议收藏」

作者头像
全栈程序员站长
发布于 2022-11-04 08:17:16
发布于 2022-11-04 08:17:16
2.8K00
代码可运行
举报
运行总次数:0
代码可运行

大家好,又见面了,我是你们的朋友全栈君。

1、简要说明

1)本文基于spring5.1.7版本,采用ApplicationContext获取bean对象。

2)BeanFactory和ApplicationContext对于bean后置处理器还有所不同,需要注意,ApplicationContext会自动检测在配置文件中实现了BeanPostProcessor接口的所有bean,并把它们注册为后置处理器,然后在容器创建bean的适当时候调用它,因此部署一个后置处理器同部署其他的bean并没有什么区别。而使用BeanFactory实现的时候,bean 后置处理器必须通过代码显式地去注册。

2、Bean的生命周期

2.1、生命周期流程图

2.2、总体概述 我们知道一个对象的生命周期:创建(实例化-初始化)-使用-销毁,而在Spring中,Bean对象周期当然遵从这一过程,但是Spring提供了许多对外接口,允许开发者对三个过程(实例化、初始化、销毁)的前后做一些操作。   这里就实例化、初始化区别做一个说明,在Spring Bean中,实例化是为bean对象开辟空间(具体可以理解为构造函数的调用),初始化则是对属性的初始化,说的具体点,这里的属性初始化应该是属性的注入(构造函数也可以有属性的初始化语句,但不属于这一部分),属性注入是通过setter方法注入属性(不管是注解方式还是bean配置property属性方式,其实质都是通过属性的setter方法实现的)。 2.3、接口及方法介绍

Bean的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类:

1)Bean自身的方法:这个包括了Bean本身调用的方法和通过配置文件中的init-method和destroy-method指定的方法

2)Bean级生命周期接口方法:BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这些接口的方法。每个Bean选择实现,可选择各自的个性化操作。

3、容器级生命周期接口方法:这个包括了InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现(前者继承自后者),一般称它们的实现类为“后处理器”。这些接口是每个bean实例化或初始化时候都会调用。

4、工厂后处理器接口方法:这些方法也是容器级别的,但它们是在上下文装置配置文件之后调用,例如BeanFactoryPostProcessor、 CustomAutowireConfigurer等。

3、具体代码实现

1)定义一个bean类(CustomBean)

它实现了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这4个接口,同时有2个方法,对应配置文件中的init-method和destroy-method。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * @author xf
 * @description 自定义bean
 * @date 2019/5/22 11:52
 */
public class CustomBean implements BeanFactoryAware,BeanNameAware,InitializingBean,DisposableBean {

    private String name;
    private String address;

    private BeanFactory beanFactory;
    private String beanName;

    public CustomBean() {
        System.out.println("第6步:【构造器】调用CustomBean的构造器实例化");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("第9步:【注入属性】注入属性name");
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        System.out.println("第10步:【注入属性】注入属性address");
        this.address = address;
    }

    @Override
    public String toString() {
        return "CustomBean{" +
                "name='" + name + '\'' +
                ", address='" + address + '\'' +
                '}';
    }

    // 通过spring的xml配置文件<bean>的init-method属性指定的初始化方法
    public void xml_init() {
        System.out.println("第16步:【init-method】调用<bean>的init-method属性指定的初始化方法");
    }

    // 通过spring的xml配置文件<bean>的destroy-method属性指定的初始化方法
    public void xml_destroy() {
        System.out.println("第21步:【destroy-method】调用<bean>的destroy-method属性指定的销毁方法");
    }

    // 这是BeanFactoryAware接口方法
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out
                .println("第12步:【执行BeanFactoryAware接口的setBeanFactory方法】setBeanName后调用");
        this.beanFactory = beanFactory;
    }

    // 这是BeanNameAware接口方法
    @Override
    public void setBeanName(String s) {
        System.out.println("第11步:【执行BeanNameAware接口的setBeanName方法】属性注入后调用, 此时s = "+s);
        this.beanName = s;
    }

    // 这是InitializingBean接口方法
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("第15步:【执行InitializingBean接口的afterPropertiesSet方法】在processBeforeInitialization之后,配置的xml_init之前调用");
    }

    // 这是DiposibleBean接口方法
    @Override
    public void destroy() throws Exception {
        System.out.println("第20步:【执行DiposibleBean接口的destroy方法】在processAfterInitialization之后,配置的xml_destroy之前调用");
    }
}

2)BeanFactoryPostProcessor类(工厂后处理器)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * @author xf
 * @description 工厂后处理器
 * @date 2019/5/22 14:05
 */
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor{

    public CustomBeanFactoryPostProcessor() {
        System.out.println("第1步:这是BeanFactoryPostProcessor(工厂后处理器)实现类CustomBeanFactoryPostProcessor的构造器!!");
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        System.out.println("第2步:调用BeanFactoryPostProcessor(工厂后处理器)实现类CustomBeanFactoryPostProcessor的方法postProcessBeanFactory。ApplicationContext容器初始化中refresh()中调用");
    }
}

3)BeanPostProcessor类

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * @author xf
 * @description BeanPostProcessor的实现类
 * @date 2019/5/22 14:06
 */
public class InitialBeanPostProcessor implements BeanPostProcessor {

    public InitialBeanPostProcessor() {
        System.out.println("第4步:这是BeanPostProcessor实现类(InitialBeanPostProcessor)的构造器!!");
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("第14步:postProcessBeforeInitialization(BeanPostProcessor接口实现类InitialBeanPostProcessor的方法)对属性进行更改, bean = " + bean.getClass());
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("第18步:postProcessAfterInitialization(BeanPostProcessor接口的方法)对属性进行更改, bean = " + bean.getClass());
        return bean;
    }
}

4)InstantiationAwareBeanPostProcessor 接口本质是BeanPostProcessor的子接口,一般我们继承Spring为其提供的适配器类InstantiationAwareBeanPostProcessor Adapter来使用它

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * @author xf
 * @description 实例化处理器
 * @date 2019/5/22 14:12
 */
public class InstanceBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {

    public InstanceBeanPostProcessor() {
        System.out.println("第3步:这是InstantiationAwareBeanPostProcessorAdapter实现类(InstanceBeanPostProcessor)构造器!!");
    }

    //实例化bean之前调用
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println("第5步:实例化"+beanClass.getName()+"之前调用,即调用"+beanClass.getName()+"类构造函数之前调用 ");
        return super.postProcessBeforeInstantiation(beanClass, beanName);
    }

    //实例化bean之后调用
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        System.out.println("第7步:返回boolean,bean实例化后调用,并且返回false则不会注入属性");
        return super.postProcessAfterInstantiation(bean, beanName);
    }

    // 设置bean的某个属性时调用
    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        System.out.println("第8步:postProcessProperties,在属性注入之前调用;beanName = " + beanName + ";属性名集合 : " + Arrays.toString(pvs.getPropertyValues()));
        return super.postProcessProperties(pvs, bean, beanName);
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("第13步:postProcessBeforeInitialization(InstantiationAwareBeanPostProcessorAdapter实现类InstanceBeanPostProcessor的方法) ");
        return super.postProcessBeforeInitialization(bean, beanName);
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("第17步:postProcessAfterInitialization(InstantiationAwareBeanPostProcessorAdapter类的实现方法) ");
        return super.postProcessAfterInitialization(bean, beanName);
    }
}

5)Spring Bean的配置文件spring-bean.xml

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?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
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

	<bean id="beanFactoryPostProcessor" class="com.spring.springbeancycle.CustomBeanFactoryPostProcessor">
	</bean>
	<bean id="instantiationAwareBeanPostProcessor" class="com.spring.springbeancycle.InstanceBeanPostProcessor">
	</bean>
	<bean id="beanPostProcessor" class="com.spring.springbeancycle.InitialBeanPostProcessor">
	</bean>
	<bean id="customBean" class="com.spring.springbeancycle.CustomBean" init-method="xml_init" destroy-method="xml_destroy">
		<property name="name" value="小明"></property>
		<property name="address" value="天涯海角"></property>
	</bean>

</beans>

6)测试类

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * @author xf
 * @description 测试类
 * @date 2019/5/22 14:23
 */
public class SpringBeanTest {
    public static void main(String[] args) {
        System.out.println("====现在开始初始化容器====");
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:spring-bean.xml");
        System.out.println("====容器初始化成功====");
        CustomBean customBean = (CustomBean)context.getBean("customBean");
        System.out.println("第19步:customBean = " + customBean);
        System.out.println("====现在开始关闭容器!====");
        ((ClassPathXmlApplicationContext)context).close();
    }
}

7)测试结果

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
第1步:这是BeanFactoryPostProcessor(工厂后处理器)实现类CustomBeanFactoryPostProcessor的构造器!!
第2步:调用BeanFactoryPostProcessor(工厂后处理器)实现类CustomBeanFactoryPostProcessor的方法postProcessBeanFactory。ApplicationContext容器初始化中refresh()中调用
第3步:这是InstantiationAwareBeanPostProcessorAdapter实现类(InstanceBeanPostProcessor)构造器!!
第4步:这是BeanPostProcessor实现类(InitialBeanPostProcessor)的构造器!!
第5步:实例化com.spring.springbeancycle.CustomBean之前调用,即调用com.spring.springbeancycle.CustomBean类构造函数之前调用 
第6步:【构造器】调用CustomBean的构造器实例化
第7步:返回boolean,bean实例化后调用,并且返回false则不会注入属性
第8步:postProcessProperties,在属性注入之前调用;beanName = customBean;属性名集合 : [bean property 'name', bean property 'address']9步:【注入属性】注入属性name
第10步:【注入属性】注入属性address
第11步:【执行BeanNameAware接口的setBeanName方法】属性注入后调用, 此时s = customBean
第12步:【执行BeanFactoryAware接口的setBeanFactory方法】setBeanName后调用
第13步:postProcessBeforeInitialization(InstantiationAwareBeanPostProcessorAdapter实现类InstanceBeanPostProcessor的方法) 
第14步:postProcessBeforeInitialization(BeanPostProcessor接口实现类InitialBeanPostProcessor的方法)对属性进行更改, bean = class com.spring.springbeancycle.CustomBean15步:【执行InitializingBean接口的afterPropertiesSet方法】在processBeforeInitialization之后,配置的xml_init之前调用
第16步:【init-method】调用<bean>的init-method属性指定的初始化方法
第17步:postProcessAfterInitialization(InstantiationAwareBeanPostProcessorAdapter类的实现方法) 
第18步:postProcessAfterInitialization(BeanPostProcessor接口的方法)对属性进行更改, bean = class com.spring.springbeancycle.CustomBean
====容器初始化成功====19步:customBean = CustomBean{name='小明', address='天涯海角'}
====现在开始关闭容器!====20步:【执行DiposibleBean接口的destroy方法】在processAfterInitialization之后,配置的xml_destroy之前调用
第21步:【destroy-method】调用<bean>的destroy-method属性指定的销毁方法
4、流程总结
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1、实例化一个Bean--也就是我们常说的new2、按照Spring上下文对实例化的Bean进行配置--也就是IOC注入;

3、如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String)方法,此处传递的就是Spring配置文件中Bean的id值

4、如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory(setBeanFactory(BeanFactory)传递的是Spring工厂自身(可以用这个方式来获取其它Bean,只需在Spring配置文件中配置一个普通的Bean就可以);

5、如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文(同样这个方式也可以实现步骤4的内容,但比4更好,因为ApplicationContext是BeanFactory的子接口,有更多的实现方法);

6、如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化结束时调用那个的方法,也可以被应用于内存或缓存技术;

7、如果Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法。

8、如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法、;

注:以上工作完成以后就可以应用这个Bean了,那这个Bean是一个Singleton的,所以一般情况下我们调用同一个id的Bean会是在内容地址相同的实例,当然在Spring配置文件中也可以配置非Singleton,这里我们不做赘述。

9、当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用那个其实现的destroy()方法;

10、最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。

参考地址: https://www.cnblogs.com/zrtqsk/p/3735273.html https://uule.iteye.com/blog/2094609 https://blog.csdn.net/a327369238/article/details/52193822 https://www.cnblogs.com/kenshinobiy/p/4652008.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年9月17日 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
SpringBoot 系列教程之事务不生效的几种 case
前面几篇博文介绍了声明式事务@Transactional的使用姿势,只知道正确的使用姿势可能还不够,还得知道什么场景下不生效,避免采坑。本文将主要介绍让事务不生效的几种 case
一灰灰blog
2020/02/18
7830
SpringBoot 系列教程之事务不生效的几种 case
SpringBoot 系列教程之事务隔离级别知识点小结
上一篇博文介绍了声明式事务@Transactional的简单使用姿势,最文章的最后给出了这个注解的多个属性,本文将着重放在事务隔离级别的知识点上,并通过实例演示不同的事务隔离级别下,脏读、不可重复读、幻读的具体场景
一灰灰blog
2020/02/18
2.1K0
SpringBoot 系列教程之事务隔离级别知识点小结
SpringBoot系列教程之事务传递属性
对于mysql而言,关于事务的主要知识点可能几种在隔离级别上;在Spring体系中,使用事务的时候,还有一个知识点事务的传递属性同样重要,本文将主要介绍7中传递属性的使用场景
一灰灰blog
2020/02/18
8080
SpringBoot系列教程之事务传递属性
SpringBoot 系列教程之编程式事务使用姿势介绍篇
前面介绍的几篇事务的博文,主要是利用@Transactional注解的声明式使用姿势,其好处在于使用简单,侵入性低,可辨识性高(一看就知道使用了事务);然而缺点也比较明显,不够灵活,稍不注意,可能就因为姿势不对,导致事务不生效
一灰灰blog
2020/02/18
1.4K0
SpringBoot 系列教程之编程式事务使用姿势介绍篇
SpringBoot系列教程JPA之update使用姿势
原文: 190623-SpringBoot系列教程JPA之update使用姿势 上面两篇博文拉开了jpa使用姿势的面纱一角,接下来我们继续往下扯,数据插入db之后,并不是说就一层不变了,就好比我在
一灰灰blog
2019/07/02
2.3K0
SpringBoot系列教程JPA之update使用姿势
Spring:声明式事务
Spring 框架对 JDBC 进行封装,使用 JdbcTemplate 方便实现对数据库操作
愷龍
2023/02/09
7380
Spring:声明式事务
Spring 框架对 JDBC 进行封装,使用 JdbcTemplate 方便实现对数据库操作
愷龍
2023/02/10
7360
Spring:声明式事务
SpringBoot高级篇JdbcTemplate之数据插入使用姿势详解
使用SpringBoot进行db操作引入几个依赖,就可以愉快的玩耍了,这里的db使用mysql,对应的pom依赖如
一灰灰blog
2019/05/26
4.1K1
SpringBoot系列教程JPA之delete使用姿势详解
常见db中的四个操作curd,前面的几篇博文分别介绍了insert,update,接下来我们看下delete的使用姿势,通过JPA可以怎样删除数据
一灰灰blog
2019/07/09
3.9K0
Spring学习笔记(五)——JdbcTemplate和spring中声明式事务
它是 spring 框架中提供的一个对象,是对原始 Jdbc API 对象的简单封装。spring 框架为我们提供了很多的操作模板类。 1. 操作关系型数据的: JdbcTemplate HibernateTemplate 2. 操作 nosql 数据库的: RedisTemplate 3. 操作消息队列的: JmsTemplate spring中的JdbcTemplate在 spring-jdbc-5.0.2.RELEASE.jar 中,我们在导包的时候,除了要导入这个 jar 包外,还需要导入一个 spring-tx-5.0.2.RELEASE.jar(它是和事务相关的)。
不愿意做鱼的小鲸鱼
2022/09/24
1.5K0
Spring学习笔记(五)——JdbcTemplate和spring中声明式事务
SpringBoot高级篇JdbcTemplate之数据查询上篇
环境依然借助前面一篇的配置,链接如: 190407-SpringBoot高级篇JdbcTemplate之数据插入使用姿势详解
一灰灰blog
2019/05/26
3.9K0
【SpringBoot DB系列】Mybatis多数据源配置与使用
上一篇博文介绍 JdbcTemplate 配置多数据源的使用姿势,在我们实际的项目开发中,使用 mybatis 来操作数据库的可能还是非常多的,本文简单的介绍一下 mybatis 中,多数据源的使用姿势
一灰灰blog
2021/01/17
1.5K0
【SpringBoot DB系列】Mybatis多数据源配置与使用
声明式事务
Spring 框架对 JDBC 进行封装,使用 JdbcTemplate 方便实现对数据库操作
一个风轻云淡
2022/11/13
5990
声明式事务
【Spring事务】声明式事务 使用详解
封装起来后,我们只需要在配置文件中进行简单的配置即可完成操作,可通过注解标注来使用事务。
.29.
2023/10/17
3700
【Spring事务】声明式事务 使用详解
Spring 事务使用详解
什么是事务?根据 维基百科事务 介绍,数据库事务(简称:事务)是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。简单来说,事务就是将一系列操作当成一个不可拆分的执行逻辑单元,这些要么都成功,要么都失败。事务具有4个属性:原子性、一致性、隔离性、持久性。称为ACID特性。
Java技术编程
2020/05/21
1.2K0
Spring:JDBC Template,声明式事务
JdbcTemplate 是 spring 框架中提供的一个模板对象,是对原始繁琐的 JDBC API 对象的简单封装。
RendaZhang
2020/09/16
1.2K0
Spring:JDBC Template,声明式事务
SpringBoot系列教程JPA之基础环境搭建
JPA(Java Persistence API)Java持久化API,是 Java 持久化的标准规范,Hibernate是持久化规范的技术实现,而Spring Data JPA是在 Hibernate 基础上封装的一款框架。JPA作为标准,实际上并没有说局限于某个固定的数据源,事实上mysql,mongo, solr都是ok的。接下来我们将介绍下springboot结合jpa 来实现mysql的curd以及更加复杂一点的sql支持
一灰灰blog
2019/07/02
6000
SpringBoot系列教程JPA之基础环境搭建
SpringBoot系列教程JPA之指定id保存
原文链接: 191119-SpringBoot系列教程JPA之指定id保存 前几天有位小伙伴问了一个很有意思的问题,使用 JPA 保存数据时,即便我指定了主键 id,但是新插入的数据主键却是 mysq
一灰灰blog
2019/11/21
3.1K0
SpringBoot高级篇JdbcTemplate之数据查询下篇
环境依然借助前面一篇的配置,链接如: 190407-SpringBoot高级篇JdbcTemplate之数据插入使用姿势详解
一灰灰blog
2019/05/26
2.4K0
SpringBoot 系列教程 Mybatis+注解整合篇
上一篇博文介绍了 SpringBoot 整合 mybatis 的过程,但是 xml 的方式,总感觉让人有点蛋疼;本文将介绍一种 noxml 的使用姿势,纯用注解的方式来支持 CURD
一灰灰blog
2020/01/15
4710
SpringBoot 系列教程 Mybatis+注解整合篇
推荐阅读
相关推荐
SpringBoot 系列教程之事务不生效的几种 case
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档