Bean的生命周期

Bean的生命周期

对于Spring来说Bean 管理指的是两个操作:Spring 创建对象和 Spirng 注入属性,其中Spring默认Bean是单例( singleton )的,在此作用域下,Spring 能够精确地知道该 Bean 何时被创建,何时初始化完成,以及何时被销毁。

而对于 prototype 作用域的 Bean,Spring 只负责创建,当容器创建了 Bean 的实例后,Bean 的实例就交给客户端代码管理,Spring 容器将不再跟踪其生命周期。每次客户端请求 prototype 作用域的 Bean 时,Spring 容器都会创建一个新的实例,并且不会管那些被配置成 prototype 作用域的 Bean 的生命周期。

Bean的实例化和初始化

jvm规范中有类的初始化与实例化:

父类的类构造器() -> 子类的类构造器() -> 父类的成员变量和实例代码块 -> 父类的构造函数 -> 子类的成员变量和实例代码块 -> 子类的构造函数。

Spring Bean的实例化和初始化:

实例化----实例化的过程是一个创建Bean的过程,即调用Bean的构造函数,单例的Bean放入单例池中。

初始化----初始化的过程是一个赋值的过程,即调用Bean的setter,设置Bean的属性。

在这里插入图片描述

Bean的生命周期图解

官方参考文档网址:

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/BeanFactory.html

Bean工厂实现应尽可能支持标准Bean生命周期接口。全套初始化方法及其标准顺序为:

1、BeanNameAware's setBeanName
2、BeanClassLoaderAware's setBeanClassLoader
3、BeanFactoryAware's setBeanFactory
4、EnvironmentAware's setEnvironment
5、EmbeddedValueResolverAware's setEmbeddedValueResolver
6、ResourceLoaderAware's setResourceLoader (仅适用于在应用程序上下文中运行的情况)
7、ApplicationEventPublisherAware's setApplicationEventPublisher (仅适用于在应用程序上下文中运行的情况)
8、MessageSourceAware's setMessageSource (仅适用于在应用程序上下文中运行的情况)
9、ApplicationContextAware's setApplicationContext (o仅适用于在应用程序上下文中运行的情况)
10、ServletContextAware's setServletContext (o仅适用于在Web应用程序上下文中运行的情况)
11、postProcessBeforeInitialization methods of BeanPostProcessor
12、InitializingBean's afterPropertiesSet
13、定制的初始化方法定义<init-method >
14、postProcessAfterInitialization methods of BeanPostProcessor


在关闭bean工厂时,以下生命周期方法适用:

1、postProcessBeforeDestruction methods of DestructionAwareBeanPostProcessors
2、DisposableBean's destroy
3、a custom destroy-method definition

bean的初始化流程

  1. Spring对Bean进行实例化(相当于程序中的new Xx())
  2. Spring将值和Bean的引用注入进Bean对应的属性中
  3. 如果Bean实现了BeanNameAware接口,Spring将Bean的ID传递给setBeanName()方法(实现BeanNameAware清主要是为了通过Bean的引用来获得Bean的ID,一般业务中是很少有用到Bean的ID的)
  4. 如果Bean实现了BeanFactoryAware接口,Spring将调用setBeanDactory(BeanFactory bf)方法并把BeanFactory容器实例作为参数传入。(实现BeanFactoryAware 主要目的是为了获取Spring容器,如Bean通过Spring容器发布事件等)
  5. 如果Bean实现了ApplicationContextAwaer接口,Spring容器将调用setApplicationContext(ApplicationContextctx)方法,把应用上下文作为参数传入.(作用与BeanFactory类似都是为了获取Spring容器,不同的是Spring容器在调用setApplicationContext方法时会把它自己作为setApplicationContext 的参数传入,而Spring容器在调用setBeanDactory前需要程序员自己指定(注入)setBeanDactory里的参数BeanFactory)
  6. 如果Bean实现了BeanPostProcess接口,Spring将调用它们的postProcessBeforeInitialization(预初始化)方法(作用是在Bean实例创建成功后对进行增强处理,如对Bean进行修改,增加某个功能)
  7. 如果Bean实现了InitializingBean接口,Spring将调用它们的afterPropertiesSet方法,作用与在配置文件中对Bean使用init-method声明初始化的作用一样,都是在Bean的全部属性设置成功后执行的初始化方法。
  8. 如果Bean实现了BeanPostProcess接口,Spring将调用它们的postProcessAfterInitialization(后初始化)方法(作用与6的一样,只不过6是在Bean初始化前执行的,而这个是在Bean初始化后执行的,时机不同)
  9. 经过以上的工作后,Bean将一直驻留在应用上下文中给应用使用,直到应用上下文被销毁
  10. 如果Bean实现了DispostbleBean接口,Spring将调用它的destory方法,作用与在配置文件中对Bean使用destory-method属性的作用一样,都是在Bean实例销毁前执行的方法。

BeanNameAware接口

1、Spring源码描述

由想要知道它们在 bean 工厂中的bean 名称的 bean 实现的接口。请注意,通常不建议对象依赖于其 bean 名称,因为这表示对外部配置的潜在脆弱依赖,以及对 Spring API 可能不必要的依赖。

2、内置函数

	/**
	 * 在创建此 bean 的 bean 工厂中设置 bean 的名称。
	 * <p>在填充普通 bean 属性之后但在初始化回调之前调用,
	 * 例如 {@link InitializingBean#afterPropertiesSet()}或自定义 init-method。
	 * 
	 * @param name 工厂中 bean 的名称。 
	 * 请注意,此名称是工厂中使用的实际 bean 名称,它可能与最初指定的名称不同:特别是对于内部 bean 名称,实际 bean 名称可能通过附加 "#... "后缀。
	 * 如果需要,使用 {@link BeanFactoryUtils#originalBeanName(String)} 方法提取原始 bean 名称(无后缀)。
	 */
	void setBeanName(String name);

BeanClassLoaderAware接口

1、Spring源码描述

 允许bean知道该bean{@link ClassLoader class loader} 的回调;也就是当前bean工厂用来加载bean类的类加载器。
 这主要是为了由框架类实现,这些类必须按名称选择application类,尽管它们可能从共享类加载器加载

2、内置函数

	/**
	 * 将该bean{@link ClassLoader class loader}提供给bean实例的回调。
	 *
	 * <p>在正常bean属性的填充之后调用<i>,但是
	 * <i>在初始化回调之前,例如
	 * {@link initializebean initializebean's}
	 * {@link initializebean#afterPropertiesSet()}
	 * 方法或自定义init方法。
	 * @param classLoader拥有的类加载器
	 */
	void setBeanClassLoader(ClassLoader classLoader);

BeanFactoryAware接口

1、Spring源码描述

该接口将由希望知道其所属{@link BeanFactory}的bean实现。
例如,bean可以通过工厂查找协作bean(依赖项查找)。注意,大多数bean将选择接收引用通过相应的bean属性或构造函数创建协作bean参数(依赖项注入)。

2、内置函数

	/**
	 * 为bean实例提供所属工厂的回调。
	 * <p>在填充普通bean属性之后调用
	 * 但在初始化回调之前,例如
	 * {@link initializebean#afterPropertiesSet()}或自定义init方法。
	 * @param beanFactory 所属的beanFactory(从不为null})。
	 * bean可以立即调用工厂中的方法。
	 * @throws BeansException 在初始化错误的情况
	 * @see BeanInitializationException
	 */
	void setBeanFactory(BeanFactory beanFactory) throws BeansException;

EnvironmentAware接口

1、Spring源码描述

该接口由希望被通知其运行所在的{@link Environment}的任何bean都可以实现。

2、内置函数

	/**
	 * 设置运行此组件的 {@code Environment} 
	 */
	void setEnvironment(Environment environment);

EmbeddedValueResolverAware接口

1、Spring源码描述

该接口将由希望收到{@code StringValueResolver}通知以解析嵌入定义值的任何对象实现。
这是通过{@code ApplicationContextAware}/{@code BeanFactoryAware}接口的完整可配置beanfactory依赖项的替代方案。

2、内置函数

	/**
     * 设置用于解析嵌入定义值的StringValueResolver。
     */
	void setEmbeddedValueResolver(StringValueResolver resolver);

BeanPostProcessor接口

1、Spring源码描述

允许自定义修改新bean实例的工厂钩子&mdash;
例如,检查标记接口或使用代理包装bean。

<p>通常是通过标记接口填充bean的后处理器
或类似程序将实现{@link#postprocessebeforeignization},
而用代理封装bean的后处理器通常
实现{@link#postProcessAfterInitialization}。
<h3>注册</h3>
<p>一个{@code ApplicationContext}可以自动检测{@code BeanPostProcessor}bean
然后将这些后处理器应用到任何bean
创造。普通的{@code BeanFactory}允许对
后处理器,将它们应用于通过bean工厂创建的所有bean。

<h3>排序</h3>
<p>{@code beanpstoprocessor}在
{@code ApplicationContext}将根据
{@link org.springframework.core.PriorityOrdered}和
{@link org.springframework.core.Ordered}语义。相反,
{@code BeanPostProcessor}以编程方式向
{@code BeanFactory}将按注册顺序应用;任何命令
通过实现
将为忽略{@code PriorityOrdered}或{@code Ordered}接口
程序注册后处理器。此外
{@link org.springframework.core.annotation.Order@Order}注释不可用
考虑了{@code BeanPostProcessor}bean。

注:

实现该接口会对所有的bean进行增强。

2、内置函数

	/**
	 * 在任何bean初始化回调之前(如InitializingBean的{@code afterPropertiesSet}或自定义init方法),
	 * 将此{@code BeanPostProcessor}应用于给定的新bean实例。bean将已经被属性值填充。
	 *
	 * 返回的bean实例可能是原始实例的包装器.
	 * 默认实现按原样返回给定的{@code bean}
	 * @param bean 新bean实例
	 * @param beanName bean的名称
	 * @return 要使用的bean实例,无论是原始实例还是包装实例;
	 * 如果 {@code null}, 不会调用后续的BeanPostProcessor
	 * @throws org.springframework.beans.BeansException 该类型的异常
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
	 */
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	/**
     * 在</i>任何bean初始化回调之后(如InitializingBean的{@code afterPropertiesSet}或自定义初始化方法),
     * 将此{@code BeanPostProcessor}应用于给定的新bean实例。bean将已经被属性值填充。
     *
     * 返回的bean实例可能是原始bean的包装器
     * 对于FactoryBean,将为FactoryBean实例和FactoryBean创建的对象调用此回调(从Spring 2.0开始)。
     * 后处理器可以通过相应的{@code  bean instanceof FactoryBean}检查来决定是应用于FactoryBean还是应用于已创建的对象,或者同时应用于两者。
     * 与所有其他{@code BeanPostProcessor}回调不同,此回调也将在{@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation}方法触发短路后调用。
     * 默认实现按原样返回给定的{@code bean}。
     * 
     * @param bean the new bean instance
     * @param beanName the name of the bean
     * @return the bean instance to use, either the original or a wrapped one;
     * if {@code null}, no subsequent BeanPostProcessors will be invoked
     * @throws org.springframework.beans.BeansException in case of errors
     * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
     * @see org.springframework.beans.factory.FactoryBean
     */
    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

InitializingBean接口

1、Spring源码描述

接口将由需要在{@link BeanFactory}设置其所有属性后作出反应的bean实现:例如,执行自定义初始化,或仅检查是否已设置所有必需属性。

实现{@code InitializingBean}的另一种方法是指定自定义init方法,例如在XML bean定义中。

2、内置函数

	/**
	 * 由包含{@code BeanFactory}的程序在设置了所有bean属性并满足{@link BeanFactoryAware}、{@code ApplicationContextAware}等条件后调用。
	 * <p>此方法允许bean实例在设置了所有bean属性后执行其整体配置验证和最终初始化。
	 * @throws Exception 如果配置错误(如未能设置基本属性)或由于任何其他原因初始化失败
	 */
	void afterPropertiesSet() throws Exception;

BeanFactoryPostProcessor接口

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JqwX0zrE-1628156899160)(D:\写项目的心得\typora_image\image-20210523142025166.png)]

1、Spring源码描述

工厂挂钩允许对应用程序上下文的bean定义进行自定义修改,以适应上下文基础bean工厂的bean属性值

对于针对系统管理员的自定义配置文件很有用,这些文件重写了在应用程序上下文中配置的Bean属性。请参阅{@link PropertyResourceConfigurer}及其具体实现,以了解可以解决此类配置需求的现成解决方案

{@code BeanFactoryPostProcessor}可以参与并进行修改bean的定义,但不能参与bean的实例化。这样做可能会导致过早的bean 实例化,从而违反了容器并造成了意想不到的副作用。 如果需要bean实例交互,请考虑实现{@link BeanPostProcessor}

注册:
{@code ApplicationContext}在其bean定义中自动检测{@code BeanFactoryPostProcessor}  bean,并在创建任何其他bean之前应用它们。 也可以通过{@code ConfigurableApplicationContext}以编程方式注册{@code BeanFactoryPostProcessor}。

排序:
在{@code ApplicationContext}中自动检测到的{@code BeanFactoryPostProcessor} bean将根据{@link org.springframework.core.PriorityOrdered}和 {@link org.springframework.core.Ordered}语义进行排序。相比之下将以注册的顺序应用通过编程方式注册了{{code BeanFactoryPostProcessor}的bean。对于以编程方式注册的后处理器,将忽略通过实现 {@code PriorityOrdered}或{@code Ordered}接口表示的任何排序语义。此外,对于{@code BeanFactoryPostProcessor} bean,不考虑{@link org.springframework.core.annotation.Order @Order}批注。

2、内置函数

此接口含有以下的函数:

/**
*在标准初始化之后,修改应用程序上下文的内部bean工厂。所有bean定义都将被加载,但是还没有实例化bean 。这甚至可以覆盖或添加属性,甚至可以用于初始化bean。
**/
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

此函数的主要作用:在实例化Bean之前修改bean的属性。

3、作用

{@code BeanFactoryPostProcessor}可以参与并进行修改bean的定义,但不能参与bean的实例化。

由Spring的源码注释可见以下几点:

​ 1、该接口的调用是在Spring容器加载了Bean的定义文件之后,在Bean实例化之前调用的。

​ 2、该接口可在Bean实例化之前修改Bean的属性。

​ 3、在注册中可以看出:可以同时配置多个BeanFactoryPostProcessor。

​ 4、在排序中可以看出:通过设置order属性来控制各个BeanFactoryPostProcessor(自动检测到的)的执行次序

4、参考代码

新建MyBean类,添加remark属性

package com.zjw.spring.beanfactorypostprocessor;


public class MyBean  {

    private String remark;

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }
}

新建MyBeanFactoryPostProcessor类,实现BeanFactoryPostProcessor接口,并重写postProcessBeanFactory方法

package com.zjw.spring.beanfactorypostprocessor;

import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
          System.out.println("调用MyBeanFactoryPostProcessor的postProcessBeanFactory");
          //得到xml配置的myBean的信息
          BeanDefinition beanDefinition = configurableListableBeanFactory.getBeanDefinition("myBean");
          //得到myBean的属性名称
          MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
          if (propertyValues.contains("remark")){
              //如果包含test这个属性,替换xml中设置的值
              propertyValues.add("remark","remark的值被修改了");
              propertyValues.setScope(BeanDefinition.SCOPE_PROTOTYPE);
          }
    }
}

新建application配置类,配置MyBeanMyBeanFactoryPostProcessor两个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="myBean" class="com.zjw.spring.beanfactorypostprocessor.MyBean">
        <property name="remark" value="测试一下啦" />
    </bean>

    <bean id="myBeanFactoryPostProcessor" class="com.zjw.spring.beanfactorypostprocessor.MyBeanFactoryPostProcessor" />

</beans>

新建测试方法

package com.zjw.spring;

import com.zjw.spring.beanfactorypostprocessor.MyBean;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestMain {

    public static void tsetBeanFactoryPostProcessor( ) {
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("application.xml");
        MyBean myBean = (MyBean) classPathXmlApplicationContext.getBean("myBean");
        System.out.println(myBean.getRemark());
    }

    public static void main(String[] args) {
        tsetBeanFactoryPostProcessor( );
    }
}

InstantiationAwareBeanPostProcessor接口

1、Spring源码描述

 {@link BeanPostProcessor}的子接口,它添加了实例化之前的回调,以及实例化之后但设置了显式属性或自动装配发生之前的回调。 

通常用于禁止特定目标bean的默认实例化,例如创建带有特殊TargetSource的代理(池目标,延迟初始化目标等),或实施其他注入策略,例如字段注入。

该接口是一个专用接口,主要供框架内部使用。建议尽可能实现简单的 {@link BeanPostProcessor}接口,或从{@link InstantiationAwareBeanPostProcessorAdapter}派生,以便屏蔽此接口的扩展。

2、内置函数

    /**
     * 
     * 在实例化目标bean之前,先应用此BeanPostProcessor。
     * 它返回的bean对象可能是代替目标bean使用的代理,有效地抑制了目标bean的默认实例化。
     * 如果此方法返回一个非空对象,则Bean创建过程将被短路。
     * 唯一应用的进一步处理是来自已配置的{{link BeanPostProcessor BeanPostProcessors}的{{link #postProcessAfterInitialization}回调。
     * 此回调将应用于bean定义和bean的类,以及应用于工厂方法的定义,在这种情况下,返回的bean类型将在此处传递。 
     * 后处理器可以实现扩展的{{link SmartInstantiationAwareBeanPostProcessor}接口,以便预测它们将在此处返回的bean对象的类型。 
     * 默认实现返回{@code null}。  
     * @param beanClass要实例化的bean的类*
     * @param beanName bean的名称
     * @return 要公开的bean对象,而不是目标bean的默认实例,*或{@code null}进行默认实例化
     */
@Nullable
	default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		return null;
	}

    /**
     * 在实例化bean之后,通过构造函数或工厂方法,在发生Spring属性填充(通过显式属性或自动装配)之前执行操作。
     * 这是在Spring的自动装配开始之前,在给定bean 实例上执行自定义字段注入的理想回调。
     * 默认实现返回{@code true}。
     *  @param bean 创建的Bean实例,尚未设置属性
     * @param beanName  bean名字
     * @return {@code true}如果应该在Bean上设置属性; {@code false} 如果应该跳过属性。正常的实现应返回{@code true}。
     * 返回{@code false}也将防止在此bean实例上调用任何后续的InstantiationAwareBeanPostProcessor 实例。
     * @throws BeansException
     */

	default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
		return true;
	}

  /**
     * 在工厂将它们应用于给定的bean之前,对给定的属性值进行后处理,而无需任何属性描述符。
     * 如果实现提供了自定义的{{link #postProcessPropertyValues}实现,则实现应返回{@code null}(默认值),否则返回{@code pvs}
     * 在此接口的将来版本中(删除了{@link #postProcessPropertyValues}),*默认实现将直接按原样返回给定的{@code pvs}。
     *
     */
	@Nullable
	default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
			throws BeansException {

		return null;
	}


	@Deprecated
	@Nullable
	default PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {

		return pvs;
	}

3、作用

由Spring源码的描述可知:

1、该接口可返回代替目标bean使用的代理对象

2、该接口的postProcessBeforeInstantiation方法在实例化之前调用,若调用结果为null,则代表该bean被实例化,中断Bean的实例化过程。

2、postProcessAfterInstantiation和postProcessPropertyValues实现Bean的属性注入

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值