【框架源码】Spring源码解析之Bean生命周期流程

news/2024/10/29 3:38:09/

在这里插入图片描述

观看本文前,我们先思考一个问题,什么是Spring的bean的生命周期?这也是我们在面试的时候,面试官常问的一个问题。

在没有Spring之前,我们创建对象的时候,采用new的方式,当对象不在被使用的时候,由Java的垃圾回收机制回收。

而 Spring 中的对象是 bean,bean 和普通的 Java 对象没啥大的区别,只不过 Spring 不再自己去 new 对象了,而是由 IoC 容器去帮助我们实例化对象并且管理它,我们需要哪个对象,去问 IoC 容器要即可。IoC 其实就是解决对象之间的耦合问题,Spring Bean 的生命周期完全由容器控制。

在这里,我们主要是针对bean 的作用域为singleton的,对于 prototype 的 bean ,Spring 在创建好交给使用者之后则不会再管理后续的生命周期。

那么bean的作用域都有哪些,我们来回顾一下。

singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。prototype : 每次请求都会创建一个新的 bean 实例。request : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效。session : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效。global-session: 全局 session 作用域,仅仅在基于 Portlet 的 web 应用中才有意义,Spring5 已经被删除。

Spring Bean 的生命周期核心就分为以下几步:

  • 实例化 Instantiation
  • 属性赋值 Populate
  • 初始化 Initialization
  • 销毁 Destruction

实例化 -> 属性赋值 -> 初始化 -> 销毁

在这里插入图片描述

ok,接下来,我们用一个bean的创建来体验下Spring Bean的生命周期。

首先,我们先来介绍下什么是FactoryBean?

FactoryBean要和BeanFactory区分开来,BeanFactory是一个Bean工厂,创建和管理bean的工厂,是顶级接口,而FactoryBean 用来自定义Bean的创建过程,完成复杂Bean的定义。

Spring中Bean主要有有两种,一个是定义普通Bean,另一个是工厂Bean(FactoryBean)。FactoryBean是一个工厂bean,可以生成某一个类型的Bean实例,通过实现该接口定制实例化bean的逻辑。

FactoryBean在Spring框架中非常重要,Spring自身就提供了70多个FactoryBean接口的实现,通过 getBean()方法返回的不是FactoryBean本身,而是FactoryBean#getObject()方法所返回的对象,相当于FactoryBean#getObject()代理了getBean()方法。

FactoryBean接口源码:

public interface FactoryBean<T> {String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";//返回由FactoryBean 创建的Bean实例,如果isSingleton()返回true,该实例会被放到Spring容器的单里缓存池中@NullableT getObject() throws Exception;//返回FactoryBean创建的Bean的类型@NullableClass<?> getObjectType();//判断Bean的作用域是singleton还是prototypedefault boolean isSingleton() {return true;}
}

案例实战

  • 配置文件中< bean >的class属性配置的实现类是FactoryBean时,通过getBean()方法返回的不是FactoryBean本身
  • 获取的是FactoryBean#getObject()方法所返回的对象,相当于FactoryBean#getObject()代理了getBean()方法。
  • 创建Order实体类
@Data
public class Order {//订单IDprivate int orderId;//订单名称private String orderName;//订单价格private int price;
}
  • 创建OrderFactoryBean
public class OrderFactoryBean implements FactoryBean<Order> {public OrderFactoryBean() {System.out.println("FactoryBean构造方法执行");}private String orderInfo;//设置orderInfopublic void setOrderInfo(String orderInfo) {this.orderInfo = orderInfo;}// 11@测试订单@7999@Overridepublic Order getObject() throws Exception {String[] split = orderInfo.split("@");Order order = new Order();order.setOrderId(Integer.parseInt(split[0]));order.setOrderName(split[1]);order.setPrice(Integer.parseInt(split[2]));return order;}//返回当前bean类型@Overridepublic Class<?> getObjectType() {return Order.class;}//返回当前bean是否为单例@Overridepublic boolean isSingleton() {return FactoryBean.super.isSingleton();}
}
  • xml配置文件
    <bean id="order" class="com.lixiang.factory.OrderFactoryBean"><property name="orderInfo" value="11@测试订单@7999"/></bean>
  • 主类测试
    public static void main(String[] args) {ApplicationContext context =  new ClassPathXmlApplicationContext("classpath*:application.xml");Order order = (Order) context.getBean("order");System.out.println(order);Object obj =  context.getBean("&order");System.out.println(obj);}

在这里插入图片描述

接下来,我们再来看一下BeanFactoryPostProcessor。

BeanFactoryPostProcessor是Spring框架中一个重要的扩展接口,可以在spring的bean创建之前,可以修改Bean的定义属性,注入第三方数据等。它是在 Spring 容器加载定义 bean 的 XML 文件之后,在 bean 实例化之前执行的,对Bean进行后置处理。它的执行逻辑在BeanFactory初始化时执行,在BeanFactory的后置处理器(BeanPostProcessor)之前执行。

作用:

  • 读取应用程序上下文(ApplicationContext)中的所有Bean定义。
  • 修改定义中的属性值等信息。
  • 对修改后的定义进行处理,使其达到预期效果。
  • 将修改后的Bean定义反馈到容器中,容器将重新执行Bean创建和初始化的过程

接口代码

//ConfigurableListableBeanFactory 可以获取bean定义信息,里面进行修改bean定义
public interface BeanFactoryPostProcessor {void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

案例实战

  • 定义一个 OrderBeanFactoryPostProcessor,修改某个 bean 从单例改为多例,然后触发init方法。
public class OrderBeanFactoryPostProcessor implements BeanFactoryPostProcessor {public OrderBeanFactoryPostProcessor(){System.out.println("OrderBeanFactoryPostProcessor构造方法执行");}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {String[] beanStr = beanFactory.getBeanDefinitionNames();for (String beanName : beanStr) {if ("order".equals(beanName)) {BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);beanDefinition.setScope(ConfigurableBeanFactory.SCOPE_SINGLETON);}}}//testInit 初始化方法public void testInit(){System.out.println("OrderBeanFactoryPostProcessor testInit 方法被调用,执行初始化逻辑");}
}
  • 配置xml
<bean id="customFactoryPostProcessor" class="com.lixiang.factory.OrderBeanFactoryPostProcessor" init-method="testInit"></bean>
  • 编写测试主类
	public static void main(String[] args) {ApplicationContext context =  new ClassPathXmlApplicationContext("classpath*:application.xml");Object obj1 =  context.getBean("&order");Object obj2 =  context.getBean("&order");System.out.println(obj1);System.out.println(obj2);}

在这里插入图片描述

Ok,说完BeanFactoryPostProcessor,我们再来看下BeanPostProcessor。

BeanPostProcessor是Spring IOC容器提供的一个扩展机制,用于拦截和修改实例化的Bean对象的过程。默认是对整个Spring容器中【所有的bean】进行处理,如果要对具体某个bean进行处理,通过方法参数判断即可。在容器实例化Bean对象后 (执行构造函数),初始化方法执行【前后】的回调方法,提供Bean实例初始化期间加入自定义逻辑。

案例实战

  • 编写OrderBeanPostProcessor
public class OrderBeanPostProcessor implements BeanPostProcessor {public OrderBeanPostProcessor() {System.out.println("BeanPostProcessor构造方法执行");}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("BeanPostProcessor postProcessAfterInitialization 调用 beanName="+beanName);if(beanName.equalsIgnoreCase("order")){Order order = (Order)bean;order.setOrderName("修改后的订单名称");return BeanPostProcessor.super.postProcessAfterInitialization(order, beanName);}return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);}
}
  • 编写xml配置Order对象属性
    <bean id="orderBeanPostProcessor" class="com.lixiang.factory.OrderBeanPostProcessor"></bean><bean id="order" class="com.lixiang.domain.Order"><property name="orderId" value="113726"/><!-- 这里我们将订单名称设置为测试订单 --><property name="orderName" value="测试订单"/> <property name="price" value="2131213"/></bean>
  • 编写测试代码
	public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:application.xml");Order order = (Order) context.getBean("order");System.out.println(order);}

在这里插入图片描述

  • 注意

    • BeanPostProcessor 是在 spring 容器加载了 bean 的定义文件,且实例化 bean 之后执行

    • BeanPostProcessor 的执行顺序是在 BeanFactoryPostProcessor 之后

    • BeanFactoryPostProcessor 和 BeanPostProcessor 都是处理 bean 的生命周期中拓展点,使用场景不同

      • BeanFactoryPostProcessor 作用于 bean 实例化之前,读取配置元数据 BeanDefinition ,且可以修改
      • BeanPostProcessor 作用于 bean 的实例化过程中,可以改变 bean 实例的值

还有几个接口,我们简单了解下,这快就不做演示了。

  • BeanNameAware
BeanNameAware接口是为了让自身Bean能够感知到,获取到自身在Spring容器中的id或name属性。让Bean获取自己在BeanFactory配置中的名字(根据情况是id或者name)。 Spring自动调用。并且会在Spring自身完成Bean配置之后,且在调用任何Bean生命周期回调(初始化或者销毁)方法之前就调用这个方法。换言之,在程序中使用BeanFactory.getBean(String beanName)之前,Bean的名字就已经设定好了。
  • BeanFactoryAware
BeanFactoryAware接口是Spring框架中的一个接口,用于在Bean实例化后,将BeanFactory实例注入到Bean中。通过实现该接口,Bean可以获取到BeanFactory实例,从而可以在运行时动态获取其他Bean的实例。具体来说,BeanFactoryAware接口的作用是让Bean能够感知到所在的BeanFactory,从而可以在需要时获取其他Bean的实例。这对于需要动态获取其他Bean的实例的情况非常有用,例如在AOP中需要获取代理对象等。
  • ApplicationContextAware
在spring项目中,类之间的关系是spring容器来管理的,但是一个项目中有些类不受spring容器管理,缺需要使用受spring管理的bean,这时候不能通过正常的方式注入bean,这时候spring给我们提供了ApplicationContextAware接口,我们可以编写一个工具类来实现ApplicationContextAware,当一个类实现ApplicationContextAware接口后,当这个类被spring加载后,就能够在这个类中获取到spring的上下文操作符ApplicationContext,通过ApplicationContext 就能够轻松的获取所有的spring管理的bean。
  • Initializingbean
Initializingbean接口只有一个afterPropertiesSet方法,实现了这个接口的类在初始化Bean时会执行这个方法。所以这个接口的用途就是用来实现初始化数据用的。public interface InitializingBean {void afterPropertiesSet() throws Exception;
}
  • DisposableBean
该接口的作用是:允许一个bean在它的所有必须属性被BeanFactory设置后,来执行初始化的工作,该接口中只有一个方法,afterPropertiesSet。public interface InitializingBean {void afterPropertiesSet() throws Exception;
}

ok,现在我们用Order实现以上的接口。

public class Order implements BeanNameAware, BeanFactoryAware,ApplicationContextAware, InitializingBean, DisposableBean {private int orderId;private String orderName;private int price;public Order() {System.out.println("Order - 构造方法执行,创建对象");}public Order(int orderId, String orderName, int price) {this.orderId = orderId;this.orderName = orderName;this.price = price;}public int getOrderId() {return orderId;}public void setOrderId(int orderId) {this.orderId = orderId;}public String getOrderName() {return orderName;}public void setOrderName(String orderName) {this.orderName = orderName;}public int getPrice() {return price;}public void setPrice(int price) {this.price = price;}@Overridepublic String toString() {return "Order{" +"orderId=" + orderId +", orderName='" + orderName + '\'' +", price=" + price +'}';}@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {System.out.println("Order - BeanFactoryAware - setBeanFactory 方法被调用");}@Overridepublic void setBeanName(String s) {System.out.println("Order - BeanNameAware - setBeanName 方法被调用");}@Overridepublic void destroy() throws Exception {System.out.println("Order - DisposableBean - destroy 方法被调用");}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("Order - InitializingBean - afterPropertiesSet 方法被调用");}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {System.out.println("Order - ApplicationContextAware - setApplicationContext 方法被调用");}
}

创建Order对象,查看方法执行调用链。

在这里插入图片描述

方法调用链图解

在这里插入图片描述

源码分析目标,关键就在于AbstractApplicationContext 类 的 refresh 方法

在这里插入图片描述

OK,接下来我们来看看refresh的源码分析,基本上整一个spring生命周期都这这个方法里执行,我们来看看这个核心方法里面都做了什么

public void refresh() throws BeansException, IllegalStateException {//采用对象锁,保证多线程环境下,在容器正在启动/关闭时, 另一个启动/关闭操作会被阻塞synchronized (this.startupShutdownMonitor) {//统计Spring应用程序的启动时间,并输出到logStartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");//1.调用子类覆盖的方法prepareRefresh(),为当前的工厂进行启动数据准备工作prepareRefresh();/*** 2.调用子类覆盖的方法obtainFreshBeanFactory(),创建新的BeanFactory, 默认实现是DefaultListableBeanFactory* 解析xml, 生成BeanDefinition 并注册到 BeanDefinitionRegistry**/ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();//3.beanFactory准备工作,调用子类覆盖的方法prepareBeanFactory(),对新的BeanFactory进行各种后置处理prepareBeanFactory(beanFactory);try {//4.beanFactory准备工作完成后,继续进行的【后置处理】postProcessBeanFactory(beanFactory);StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");//5.BeanFactoryPostProcessor//Spring 启动时查找所有实现 BeanFactoryPostProcessor 接口的类,并逐一调用其 postProcessBeanFactory 方法invokeBeanFactoryPostProcessors(beanFactory);//6.BeanPostProcessor//注册 BeanPostProcessor,负责为该 Bean 对象创建代理对象registerBeanPostProcessors(beanFactory);beanPostProcess.end();//7.初始化信息源,用来支持国际化initMessageSource();//8.初始化事件广播器,用来支持了Spring事件机制initApplicationEventMulticaster();//9.留给子类实现的初始化操作,即调用自定义的回调方法onRefresh();//10.注册实现了ApplicationListener接口的类registerListeners();/*** 11.实例化所有剩余的单例Bean(非懒加载的单例bean),注意这里要区分单例和非单例Bean,主要下面的工作*    填充属性*    调用初始化方法 afterPropertiesSet、init-method方法*    调用BeanPostProcessor 后置处理器 postProcessBeforeInitialization和postProcessAfterInitialization执行*/finishBeanFactoryInitialization(beanFactory);//12.事件发布,发送ContextRefreshedEvent事件finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.// 销毁已经创建的单例beandestroyBeans();// 将 context 的 active 属性重置为 falsecancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...// 重置Spring IOC中的共享缓存,避免单例bean的引用问题resetCommonCaches();//更新contextRefresh的状态contextRefresh.end();}}}

总结

  • 首先根据配置情况调用 Bean 构造方法或工厂方法实例化 Bean。

  • 然后利用反射创建对象设置Bean 中所有属性值的配置注入。

  • 如果 Bean 实现了 BeanNameAware 接口,则 Spring 调用 Bean 的 setBeanName() 方法传入当前 Bean 的 id 值。

  • 如果 Bean 实现了 BeanFactoryAware 接口,则 Spring 调用 setBeanFactory() 方法传入当前工厂实例的引用。

  • 如果 Bean 实现了 ApplicationContextAware 接口,则 Spring 调用 setApplicationContext() 方法传入当前 ApplicationContext 实例的引用。

  • 如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的预初始化方法 postProcessBeforeInitialzation() 对 Bean 进行加工操作,此处非常重要,Spring 的 AOP 就是利用它实现的。

  • 如果 Bean 实现了 InitializingBean 接口,则 Spring 将调用 afterPropertiesSet() 方法,如果在配置文件中通过 init-method 属性指定了初始化方法,则调用该初始化方法。

  • 如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的初始化方法 postProcessAfterInitialization()。此时,Bean 已经可以被应用系统使用了。

  • 如果在 中指定了该 Bean 的作用范围为 scope=“singleton”,则将该 Bean 放入 Spring IoC 的缓存池中,将触发 Spring 对该 Bean 的生命周期管理;如果在 中指定了该 Bean 的作用范围为 scope=“prototype”,则将该 Bean 交给调用者,调用者管理该 Bean 的生命周期,Spring 不再管理该 Bean。

  • 如果 Bean 实现了 DisposableBean 接口,则 Spring 会调用 destory() 方法将 Spring 中的 Bean 销毁;如果在配置文件中通过 destory-method 属性指定了 Bean 的销毁方法,则 Spring 将调用该方法对 Bean 进行销毁。

ok,那么至此,Spring Bean的整一个生命周期全部解析完成。
在这里插入图片描述


http://www.ppmy.cn/news/222838.html

相关文章

【Vue】详解Vue生命周期

Vue实例的生命周期全过程&#xff08;图&#xff09; &#xff08;这里的红边圆角矩形内的都是对应的Vue实例的钩子函数&#xff09; 在beforeCreate和created钩子函数间的生命周期 在beforeCreate和created之间&#xff0c;进行数据观测(data observer) &#xff0c;也就是在这…

图书购物商城 图书后台管理系统

图书购物商城 图书后台管理系统 这个图书购物商城系统是一个基于JSP、Servlet和MySQL技术开发的综合性系统&#xff0c;它包括前台和后台功能。该系统旨在为用户提供一个便捷的购书平台&#xff0c;同时为管理员提供管理图书和订单的功能。 前台部分是用户使用的界面&#xf…

过去、现在及未来

人生最邪恶的地方在于&#xff0c;只能年轻一次 回顾下我毫无规划的&#xff0c;且已经消耗掉的青春 一&#xff1a;过去 19岁&#xff0c;进入大学&#xff0c;兼职、玩儿、暧昧 20-21岁&#xff0c;初创软件公司打杂、恋爱、暧昧 22、23、24岁&#xff0c;上海&#xff…

SQL-基础

SQL-小基础 1 SQL简介 英文&#xff1a;Structured Query Language&#xff0c;简称 SQL结构化查询语言&#xff0c;一门操作关系型数据库的编程语言定义操作所有关系型数据库的统一标准对于同一个需求&#xff0c;每一种数据库操作的方式可能会存在一些不一样的地方&#xff…

06.05

1.二进制求和 给你两个二进制字符串 a 和 b &#xff0c;以二进制字符串的形式返回它们的和。 考虑一个最朴素的方法&#xff1a;先将 aaa 和 bbb 转化成十进制数&#xff0c;求和后再转化为二进制数。利用 Python 和 Java 自带的高精度运算&#xff0c;我们可以很简单地写出这…

NIMA: Neural Image Assessment

摘要:基于自动学习的图像质量评估技术在评价图像采集管道、存储技术和共享媒体等方面具有广泛的应用价值&#xff0c;近年来已成为图像质量评估研究的热点。尽管这一问题具有主观性&#xff0c;但现有的大多数方法仅对AVA[1]和TID2013[2]等数据集提供的平均意见得分进行预测。我…

哪些蓝牙耳机便宜好用?实惠好用的蓝牙耳机推荐

现在无线蓝牙耳机可以轻松实现移动中通话和听音乐&#xff0c;享受充分的无线自由&#xff0c;多数人购买蓝牙耳机对于音质有要求以及好用以外&#xff0c;当然还有性价比&#xff0c;下面我来推荐几款实惠好用的蓝牙耳机。 一、南卡lite pro2蓝牙耳机 NANK南卡是我国的国产品…

低噪放大器

0 引言 在雷达射频接收系统中&#xff0c;对系统性能指标的要求越来越高&#xff0c;其中低噪声放大器是影响着整个接收系统的噪声指标的重要因素。与普通的放大器相比&#xff0c;低噪声放大器作用比较突出&#xff0c;一方面可以减少系统的杂波干扰&#xff0c;提高系统的灵敏…