当前位置: 首页 > news >正文

Spring中Bean的完整生命周期!(Bean实例化的流程,Spring后处理器,循环依赖解释及解决方法)附案例演示

Bean实例化的基本流程

  1. 加载xml配置文件,解析获取配置中的每个的信息,封装成一个个的BeanDefinition对象
  2. 将BeanDefinition存储在一个名为beanDefinitionMap的Map<String,BeanDefinition>中
  3. ApplicationContext底层遍历beanDefinitionMap,创建Bean实例对象
  4. 创建好的Bean实例对象,被存储到一个名为singletonObjects的Map<String,Object>中当执行applicationContext.getBean(beanName)时,从singletonObjects去匹配Bean实例返回

在这里插入图片描述

Spring的后处理器

Spring的后处理器是Spring对外开发的重要扩展点,允许我们介入到Bean的整个实例化流程中来,以达到动态注册BeanDefinition,动态修改BeanDefinition,以及动态修改Bean的作用。Spring主要有两种后处理器:

  • BeanFactoryPostProcessor:Bean工厂后处理器,在BeanDefinitionMap填充完毕,Bean实例化之前执行;
  • BeanPostProcessor:Bean后处理器,一般在Bean实例化之后,填充到单例池singletonObjects之前执行

BeanFactoryPostProcessor

  • Bean工厂后处理器——BeanFactoryPostProcessor

    BeanFactoryPostProcessor是一个接口规范,实现了该接口的类只要交由Spring容器管理的话,那么Spring就会回调该接口的方法,用于对BeanDefinition注册修改的功能

    注册&修改

    假如现在有User和Student两个Bean,且Student已经注入容器

    public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {System.out.println("MyBeanFactoryPostProcessor的BeanFactoryPostPostProcessor");/*修改*/BeanDefinition student = beanFactory.getBeanDefinition("student");student.setBeanClassName("com.dong.bean.User");/*注册*/RootBeanDefinition definition = new RootBeanDefinition();definition.setBeanClassName("com.dong.bean.Student");DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory;defaultListableBeanFactory.registerBeanDefinition("student2",definition);}
    }
    
    • 修改:将id为student的类型改为了User类型
    • 注册:又注入了一个id为student2的Student对象
    • 注:需要将工厂后处理器注入容器

    配置文件

    <?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="student" class="com.dong.bean.Student"></bean><bean id="beanFactoryPostProcessor" class="com.dong.processor.MyBeanFactoryPostProcessor"></bean>
    </beans>
    
  • Bean工厂后处理器——BeanDefinitionRegistryPostProcessor

    Spring 提供了一个BeanFactoryPostProcessor的子接口BeanDefinitionRegistryPostProcessor专门用于注册BeanDefinition操作

    public class MyBeanFactoryPostProcessor2 implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {BeanDefinition beanDefinition = new RootBeanDefinition();beanDefinition.setBeanClassName("com.dong.bean.Student"); beanDefinitionRegistry.registerBeanDefinition("student3",beanDefinition);}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {}
    }
    
    • postProcessBeanDefinitionRegistry方法:注册BeanDefinition

    配置文件注入Bean后工厂处理器

    <?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="student" class="com.dong.bean.Student"></bean><bean id="beanFactoryPostProcessor2" class="com.dong.processor.MyBeanFactoryPostProcessor2"></bean>
    </beans>
    

在这里插入图片描述

BeanPostProcessor

Bean被实例化后,到最终缓存到名为singletonObjects单例池之前,中间会经过Bean的初始化过程,例如:属性的填充、初始方法init的执行等,其中有一个对外进行扩展的点BeanPostProcessor,我们称为Bean后处理。跟上面的 Bean工厂后处理器相似,它也是一个接口,实现了该接口并被容器管理的BeanPostProcessor,会在流程节点上被Spring自动调用。

实现:

public class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("BeanPostProcessor的before方法...");return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("BeanPostProcessor的after方法...");return bean;}
}

配置文件配置Bean后处理

<?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="student" class="com.dong.bean.Student"></bean><bean id="beanPostProcessor" class="com.dong.processor.MyBeanPostProcessor"></bean>
</beans>
public class Test01 {public static void main(String[] args) {ApplicationContext appliactionContext = new ClassPathXmlApplicationContext("applicationContext.xml");Student student = (Student) appliactionContext.getBean("student");System.out.println(student);}
}

输出结果:

student的无参构造
BeanPostProcessor的before方法…
BeanPostProcessor的after方法…
com.dong.bean.Student@5cb9f472

在这里插入图片描述

SpringBean完整的生命周期

Spring Bean的生命周期是从 Bean 实例化之后,即通过反射创建出对象之后,到Bean成为一个完整对象,最终存储到单例池中,这个过程被称为Spring Bean的生命周期。Spring Bean的生命周期大体上分为三个阶段

  • Bean的实例化阶段:Spring框架会取出BeanDefinition的信息进行判断当前Bean的范围是否是singleton的, 是否不是延迟加载的,是否不是FactoryBean等,最终将一个普通的singleton的Bean通过反射进行实例化
  • Bean的初始化阶段:Bean创建之后还仅仅是个"半成品",还需要对Bean实例的属性进行填充、执行一些Aware 接口方法、执行BeanPostProcessor方法、执行InitializingBean接口的初始化方法、执行自定义初始化init方法等。该阶段是Spring最具技术含量和复杂度的阶段
  • Bean的完成阶段:经过初始化阶段,Bean就成为了一个完整的Spring Bean,被存储到单例池singletonObjects中去了,即完成了Spring Bean的整个生命周期

由于Bean的初始化阶段的步骤比较复杂,所以着重研究Bean的初始化阶段

  • Bean实例的属性填充
  • Aware接口属性注入
  • BeanPostProcessor的before()方法回调
  • InitializingBean接口的初始化方法回调
  • 自定义初始化方法init回调
  • BeanPostProcessor的after()方法回调

Bean实例的填充

Spring在进行属性注入时,会分为如下几种情况:

  1. 注入普通属性,String、int或存储基本类型的集合时,直接通过set方法的反射设置进去;
  2. 注入单向对象引用属性时,从容器中getBean获取后通过set方法反射设置进去,如果容器中没有,则先创建被注入对象Bean实例(完成整个生命周期)后,在进行注入操作
  3. 注入双向对象引用属性时,就比较复杂了,涉及了循环引用(循环依赖)

循环依赖

注入双向对象引用属性时就会出现循环依赖

循环依赖:多个实体之间相互依赖并形成闭环的情况就叫做"循环依赖",也叫做"循环引用"

在这里插入图片描述

在这里插入图片描述

循环依赖问题spring已经给出了解决方法:三级缓存

Spring提供了三级缓存存储 完整Bean实例 和 半成品Bean实例 ,用于解决循环引用问题

在DefaultListableBeanFactory的上四级父类DefaultSingletonBeanRegistry中提供如下三个Map

在这里插入图片描述

假如,UserService注入了一个UserDao,UserDao又注入了一个UserService,实例化过程如下:

  • UserService 实例化对象,但尚未初始化,将UserService存储到三级缓存
  • UserService 属性注入,需要UserDao,从缓存中获取,没有UserDao
  • UserDao实例化对象,但尚未初始化,将UserDao存储到到三级缓存
  • UserDao属性注入,需要UserService,从三级缓存获取UserService,UserService从三级缓存移入二级缓存
  • UserDao执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存
  • UserService 注入UserDao
  • UserService执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存

常用的Aware接口

Aware接口是一种框架辅助属性注入的一种思想,其他框架中也可以看到类似的接口。框架具备高度封装性,我们接触到的一般都是业务代码,一个底层功能API不能轻易的获取到,但是这不意味着永远用不到这些对象,如果用到了 ,就可以使用框架提供的类似Aware的接口,让框架给我们注入该对象

总结:处理器的作用,为Bean生命周期各个阶段提供扩展

在这里插入图片描述

Bean生命周期总结

在这里插入图片描述

  1. 先读取配置文件,封装BeanDefinition信息对象,将BeanDefinition对象存到BeanDefinitionMap中,执行Bean后工厂处理器
  2. Bean的实例化阶段,Bean实例化了,但是未执行属性填充等生命周期过程,是个半成品
  3. 执行属性赋值,Aware接口方法回调等等周期
  4. Bean的初始化阶段,该阶段对Bean进行生命周期过程执行,spring大多数功能增强,例如注解解析,AOP都在此完成
  5. Bean的存储阶段,实例化并初始化好的Bean存储到单利池singletonObjects中

案例演示完整生命周期

  1. 导入坐标:spring context

  2. 创建实体类:Student,实现接口:InitializingBean,BeanFactoryAware,BeanNameAware,ApplicationContextAware

    public class Student implements InitializingBean,BeanFactoryAware,BeanNameAware,ApplicationContextAware{private String sname;public Student() {System.out.println("bean的无参构造方法");}public void setSname(String sname) {System.out.println("set方法赋值");this.sname = sname;}public void doinit(){System.out.println("方法初始化");}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("接口的初始化方法");}@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {System.out.println("BeanFactoryAware接口");}@Overridepublic void setBeanName(String s) {System.out.println("BeanNameAware接口");}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {System.out.println("ApplicationContextAware接口");}
    }
    
  3. 创建bean后处理类

    public class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("Bean的后处理的postProcessBeforeInitialization方法");return null;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("Bean的后处理的postProcessAfterInitialization方法");return null;}
    }
    
  4. spring主配置文件

    <?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="student" class="com.dong.bean.Student" init-method="doinit"><property name="sname" value="张三"></property></bean><bean id="beanPostProcessor" class="com.dong.provessor.MyBeanPostProcessor"></bean></beans>
    
  5. 测试:getBean注入的Student

    public class Test01 {public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");Student student = (Student) applicationContext.getBean("student");System.out.println(student);}
    }
    
  6. 输入结果:

    bean的无参构造方法
    set方法赋值
    BeanNameAware接口
    BeanFactoryAware接口
    ApplicationContextAware接口
    Bean的后处理的postProcessBeforeInitialization方法
    接口的初始化方法
    方法初始化
    Bean的后处理的postProcessAfterInitialization方法
    com.dong.bean.Student@6536e911

http://www.lryc.cn/news/212809.html

相关文章:

  • AcWing第 127 场周赛 - AcWing 5283. 牛棚入住+AcWing 5284. 构造矩阵 - 模拟+快速幂+数学
  • 2023-10-31 游戏开发-微信小游戏-文档记录
  • 2023NOIP A层联测21-异或
  • 分布式存储系统Ceph应用组件介绍
  • 【数据结构】数组和字符串(十一):字符串的定义与存储(顺序存储、链式存储及其C语言实现)
  • zk-Bench:SNARKs性能对比评估工具
  • 【Linux】NTP服务器配置、时间修改
  • 毕业设计基于SpringMVC+Mybatis+Bootstrap的电影院管理系统源码+数据库
  • vantUI(Tabbar标签页)浏览器返回上一页的失效问题
  • 【算法】Prim算法(求最小生成树)
  • go语言,yaml实现简单的workflow工作流
  • BaiduMallServcie
  • vue3+jsx+antd的插槽写法之一
  • Shell 学习之 if 命令
  • android 同步 服务器 时间
  • 10、电路综合-基于简化实频的宽带匹配电路设计方法
  • N-130基于springboot,vue校园社团管理系统
  • Syntax Error: TypeError: this.getOptions is not a function的解决(Vue)
  • 使用 kube-downscaler 降低Kubernetes集群成本
  • LeetCode热题100——哈希表
  • Kubeadm
  • 【Overload游戏引擎细节分析】PBR材质Shader---完结篇
  • C++设计模式_18_State 状态模式
  • 详解final, abstract, interface关键字
  • 统计特殊四元组
  • 腾讯云轻量应用服务器“镜像”怎么选择合适?
  • Ruby模块和程序组织
  • 14、SpringCloud -- WebSocket 实时通知用户
  • 智能井盖传感器推荐,万宾科技助力城市信息化建设
  • 3D模型格式转换工具HOOPS Exchange对工业级3D产品HOOPS的支持与应用