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

news/2024/7/24 9:11:09 标签: spring, python, java

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已经注入容器

    java">public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
        @Override
        public 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操作

    java">public class MyBeanFactoryPostProcessor2 implements BeanDefinitionRegistryPostProcessor {
        @Override
        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
            BeanDefinition beanDefinition = new RootBeanDefinition();
            beanDefinition.setBeanClassName("com.dong.bean.Student"); beanDefinitionRegistry.registerBeanDefinition("student3",beanDefinition);
        }
    
        @Override
        public 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自动调用。

实现:

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

    @Override
    public 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>
java">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

    java">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("方法初始化");
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("接口的初始化方法");
        }
    
        @Override
        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
            System.out.println("BeanFactoryAware接口");
        }
    
        @Override
        public void setBeanName(String s) {
            System.out.println("BeanNameAware接口");
        }
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            System.out.println("ApplicationContextAware接口");
        }
    }
    
  3. 创建bean后处理类

    java">public class MyBeanPostProcessor implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("Bean的后处理的postProcessBeforeInitialization方法");
            return null;
        }
    
        @Override
        public 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

    java">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.niftyadmin.cn/n/5134037.html

相关文章

Java I/O (输入/输出)

1.流的概念 流是一种有序的数据序列&#xff0c;根据操作类型&#xff0c;可以分为输入流和输出流两种。I/O流&#xff08;输入输出&#xff09;提供了一条通道程序&#xff0c;可以使用这条通道把源中的字节序列送到目的地。 1.1 输入流&#xff1a; 程序从指向源的输入流中读…

基于SpringBoot的图书电子商务网站设计与实现

目录 前言 一、技术栈 二、系统功能介绍 管理员功能实现 用户管理 图书分类管理 图书信息管理 订单管理 用户功能实现 图书信息 购物车 确认下单 我的收藏 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 社会发展日新月异&#xff0c;用计算机应用…

0034Java程序设计-基于Java的飞机大战游戏的设计与实现论文

文章目录 摘 要目 录系统设计开发环境 摘 要 现如今&#xff0c;随着智能手机的兴起与普及&#xff0c;加上4G&#xff08;the 4th Generation mobile communication &#xff0c;第四代移动通信技术&#xff09;网络的深入&#xff0c;越来越多的IT行业开始向手机行业转移重心…

Docker:安装MySQL

Docker&#xff1a;安装MySQL 1. 部署MySQL2.部署多个MySQL服务 1. 部署MySQL 首先需要安装Docker&#xff0c;安装Docker地址&#xff1a;http://t.csdnimg.cn/utPGF 安装命令&#xff1a; docker run -d \--name mysql \-p 3306:3306 \-e TZAsia/Shanghai \-e MYSQL_ROOT…

MySQL WITH AS及递归查询

MySQL WITH AS及递归查询 WITH AS 官网&#xff1a;WITH 是 SQL 中的一个关键字&#xff0c;用于创建临时表达式&#xff08;也称为 Common Table Expression&#xff0c;CTE&#xff09;&#xff0c;它允许你在一个查询中临时定义一个表达式&#xff0c;然后在后续的查询中引…

C- struct stat 获取文件状态信息的结构体

基本概念 struct stat 是 C 语言中用于获取文件状态信息的结构体。它在 <sys/stat.h> 头文件中定义&#xff0c;主要通过 stat(), fstat(), 和 lstat() 等函数来填充其字段。以下是 struct stat 的详细信息&#xff1a; 定义: struct stat {dev_t st_dev; /* …

微信小程序云开发如何优雅的实现模糊查询

微信官方自从推出微信小程序云开发之后&#xff0c;让小程序开发的门槛再次降低&#xff0c;你可以不需要掌握任何后端的语言和数据库&#xff0c;有一些js的基本功&#xff0c;就可以完成一个完整带前后端交互功能的小程序项目。今天我们介绍一个日常开发中非常常见的需求&…

一周通过Professional Scrum Master(PSM1)考试准备分享

目录 一、为什么要考PSM 二、考试培训费用 三、学习时间 四、备考流程 1.通读Scrum Guide 2.完成Scrum Open的练习题3次 3.找题库刷题 4.再次完成Scrum Open的练习题3次 5.正式参加考试 五、其他考试准备 1.考试资格购买 2.语言 六、后记 一、为什么要考PSM 市面上有不少…