Spring中Bean实例化的过程

在SpringBean的生命周期中,Bean的实例化阶段就是Spring将Bean给生产出来的这个过程,本文将对Bean的实例化过程进行概述。

简要来说,Spring首先通过输入流读取了Xml配置文件的信息,而后通过反射的方式将Bean实例化,但在这过程中,Spring是怎么做的,又做了什么,才是重点内容,接下来将展开描述该部分。


Bean实例化过程概览

  1. 读取Xml文件
  2. Spring将配置好的Bean的信息先封装为BeanDefinition
  3. 将其存储在Map集合BeanDefinitionMap中
  4. Bean工厂后处理器(BeanFactoryPostProcessor)
  5. 循环遍历Map集合
    1. 获取到Bean的信息,通过反射的方式实例化Bean并注入属性
    2. Bean后处理器(BeanPostProcessor)
  6. 实例化阶段完成

BeanDefinition

BeanDefinition中封装了Bean的配置信息,包含类名、别名、作用域等Bean的属性。Spring将从配置文件中读取到的信息封装为BeanDefinition,将这些封装后的内容存放入BeanDefinitionMap集合中。这样在后续就可以通过遍历该集合,获取到各个Bean的信息,从而进行实例化、配置装配等操作。


后处理器

后处理器是Spring提供的,可以对IoC容器实现扩展的接口,这种接口分为两种,分别是Bean后处理器与Bean工厂后处理器,它们各自的执行时机不同,操作对象也不同。后处理器是一种特殊的Bean,只需要将其写入配置,即可在既定的时机执行操作。


BeanFactoryPostProcessor

该接口是Spring提供的可以对BeanFactory进行操作的后处理器,实现该接口并将其配置为Bean,即可在BeanDefinitionMap装配完成后,Bean实例化之前,执行其下的postProcessorBeanFactory方法。在该方法中,可以对容器进行操作,例如注册新的Bean等。

示例:

创建两个类,添加构造方法方便观察。

public class BeanA {

    //构造方法
    public BeanA() {
        System.out.println("beanA实例化");
    }

}

public class BeanB {

    //构造方法
    public BeanB() {
        System.out.println("beanB实例化");
    }

}

创建类实现BeanFactoryPostProcessor接口并重写方法。

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        /*
         * 观察是否可以获取BeanDefinition
         * 如果可以获取,则说明此时BeanDefinitionMap已装配完毕
         */
        String beanA = beanFactory.getBeanDefinition("beanA").getBeanClassName();
        String beanB = beanFactory.getBeanDefinition("beanB").getBeanClassName();
        System.out.println(beanA);
        System.out.println(beanB);
        //为方便观察,输出语句
        System.out.println("Bean工厂后处理器");
    }
}

将这些类在Xml文件中配置为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工厂后处理器配置为Bean -->
    <bean class="com.stlg.MyBeanFactoryPostProcessor"/>

    <bean id="beanA" class="com.stlg.bean.BeanA"/>

    <bean id="beanB" class="com.stlg.bean.BeanB"/>

</beans>

在测试类中加载容器,观察执行结果。

 可以观察到,在后处理器执行时,已经可以正常获取到BeanDefinition了,这说明BeanDefinition已经装配进BeanDefinitionMap集合中了,而Bean工厂后处理器结束后beanA与beanB逐个被实例化。这说明Bean工厂后处理器是在BeanDefinition装配完毕后,Bean实例化之前执行的。


该接口下还有一个值得注意的子接口BeanDefinitionRegistryPostProcessor,这个接口的实现类下的postProcessBeanDefinitionRegistry方法会在postProcessorBeanFactory方法前执行,在该方法中可以直接进行Bean的注册。

示例:

创建类BeanC,同样添加构造方法。

创建类并实现BeanDefinitionRegistryPostProcessor接口,重写方法。

public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        //注册BeanC
        registry.registerBeanDefinition("beanC", new RootBeanDefinition("com.stlg.bean.BeanC"));
        System.out.println("注册BeanC");
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("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工厂后处理器配置为Bean -->
    <bean class="com.stlg.MyBeanFactoryPostProcessor"/>
    <bean class="com.stlg.MyBeanDefinitionRegistryPostProcessor"/>

    <bean id="beanA" class="com.stlg.bean.BeanA"/>

    <bean id="beanB" class="com.stlg.bean.BeanB"/>

</beans>

再次查看运行结果,观察BeanFactoryPostProcessor与BeanDefinitionRegistryPostProcessor的执行时机。

可以清楚地看到,BeanC虽然没有被配置到Xml文件中,但在后处理器中仍然注册且能够获取到。

观察可以发现,BeanDefinitionRegistryPostProcessor下的方法与BeanFactoryPostProcessor下的方法执行顺序为:

  1. postProcessBeanDefinitionRegistry
  2. postProcessBeanFactory---BeanDefinitionRegistryPostProcessor
  3. postProcessBeanFactory---BeanFactoryPostProcessor

Bean实例化阶段

在Bean工厂后处理器的操作结束后,也就代表着Bean的初始配置信息已经确定,接下来就要进行实例化阶段了。在这时候Spring会对BeanDefinitionMap容器进行遍历,获取到每个BeanDefinition并抽取出Bean的信息,依次通过反射进行实例化并进行属性注入,但此时的Bean仅仅是一个半成品,要进入下一个阶段对Bean进行完善和强化。


BeanPostProcessor

该接口是Spring提供的可以对实例化后的Bean进行操作的后处理器,实现该接口并将其配置为Bean,即可在Bean被实例化后,放入容器前,进行一系列操作。该接口下有两个方法:postProcessBeforeInitialization与postProcessAfterInitialization,顾名思义,两个方法执行时机分别为初始化操作前后。

在循环遍历BeanDefinitionMap中,每将一个Bean实例化后,都会执行这个后处理器对Bean进行强化等操作。在后处理器期间会执行Bean自定义初始化操作。这一系列操作完成后,才算一个完整的Bean,可以放入容器中。

示例:

为BeanA与BeanB添加初始化方法。

public class BeanA {

    private String desc;

    //构造方法
    public BeanA() {
        System.out.println("beanA实例化");
    }

    //初始化方法
    public void init() {
        System.out.println("beanA初始化");
    }

}


public class BeanB {

    //构造方法
    public BeanB() {
        System.out.println("beanB实例化");
    }

    //初始化方法
    public void init() {
        System.out.println("beanB初始化");
    }

}

 创建类并实现BeanPostProcessor接口,重写方法。

public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        //输出语句方便观察执行时机
        System.out.println("beforeInitialization...");
        //暂时不做操作直接返回,下同
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("afterInitialization...");
        return bean;
    }
}

 在Xml文件中进行配置。

<?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后处理器配置为Bean -->
    <bean class="com.stlg.MyBeanPostProcessor"/>

    <bean id="beanA" class="com.stlg.bean.BeanA" init-method="init"/>

    <bean id="beanB" class="com.stlg.bean.BeanB" init-method="init"/>

</beans>

运行并查看结果,观察各方法运行时机。

可以发现一个Bean在实例化后会执行后处理器的beforeInitialization方法,而后进行初始化操作,最后执行afterInitialization方法。执行完成后才会进行下一个Bean的流程。


总结

首先我们写在Xml文件中的配置会被Spring使用输入流读取,Spring将读取到的Bean的配置信息封装为BeanDefinition并放入Map集合BeanDefinitionMap中。

而后Bean工厂后处理器开始执行,此阶段可对BeanFactory进行强化或注册新的Bean等其他操作(如果实现BeanDefinitionRegistryPostProcessor接口会优先执行)。

接着Spring将循环从BeanDefinitionMap中获取BeanDefinition,提取配置信息并进行实例化。

在每个Bean被实例化后,均开始执行Bean后处理器,此阶段可以对Bean进行强化修改等操作。且在Bean初始化前后均可进行操作。

在执行完毕后,一个完整的Bean被放入容器,继续进行下一个Bean的完善,直到所有的Bean均执行完毕。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值