其他分享
首页 > 其他分享> > bean的创建过程分析-finishBeanFactoryInitialization-01

bean的创建过程分析-finishBeanFactoryInitialization-01

作者:互联网

bean的创建过程分析-finishBeanFactoryInitialization-01

我们都知道spring中有两个启动类, 分别是 ClassPathXmlApplicationContextFileSystemXmlApplicationContext

通常我们实际使用比较多得启动类就是 ClassPathXmlApplicationContext。下面我们就来先简单的回忆一下该启动类启动的核心流程。

0、前言概述

我们先来看一下类的继承关系图 ,这里一定要知道 ClassPathXmlApplicationContext 构造方法中调用的refresh() 方法是父类AbstractXmlApplicationContext 类中的refresh() 方法。

image-20220503134325821

我们都知道,要想搞懂spring源码,必须要搞清楚refresh() 源码。下图就是展示了大致的一个如何走到refresh() 方法的流程

image-20220503135441842

然后今天我们主要讲解的就是refresh方法中执行的finishBeanFactoryInitialization(beanFactory) 这一步。

1、finishBeanFactoryInitialization(beanFactory); 初始化bean讲解

finishBeanFactoryInitialization 方法中,依然是隶属于 AbstractApplicationContext

refresh()方法中一共执行了13个方法,今天我们具体讲讲 finishBeanFactoryInitialization(beanFactory); 这个方法 是如何实例化bean的过程。

image-20220503142238591

1.1、第一部分概述 - ConversionService 处理

这部分,主要是向 spring 容器中添加 beanFactory 添加 一些类型转换服务, 具体的细节参见:

    // Initialize conversion service for this context.
		// 为上下文初始化类型转换器
		if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
				beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
			beanFactory.setConversionService(
					beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
		}

Spring中类型转换服务ConversionService 以及 Converter 类型转换器

1.2、第二部分概述 - EmbeddedValueResolver 处理

这部分, 主要判断是否有 EmbeddedValueResolver 内嵌式值处理器,如果没有的话, 就添加该处理器

实际上,我们在 执行 invokeBeanFactoryPostProcessor(beanFactory) 的时候, 就已经处理过这部分了, 所以一般是进不来的,更多的是起到安全性考虑的保护作用。


if (!beanFactory.hasEmbeddedValueResolver()) {
			beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
		}

image-20220506231338083

image-20220506231531888

1.3、第三部分概述-LoadTimeWeaverAware 处理

    // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
		// 尽早初始化loadTimeWeaverAware bean,以便尽早注册它们的转换器
		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
		for (String weaverAwareName : weaverAwareNames) {
			getBean(weaverAwareName);
		}

image-20220506232318248

其实这部分中的 LoadTimeWeaverAware 主要是为了后面的面向切面服务的, 其实我们在prepareBeanFactory 环节中就已经添加了相应的织入执行器

image-20220506233118349

正如截图中的注解所言:

1.4、第四部分概述- TempClassLoader & freezeConfiguration

image-20220506233443960

这部分怎么理解呢?

1.5、第五部分概述- preInstantiateSingletons

这个步骤非常重要, 核心作用就是预先实例化所有单例bean

    // 实例化剩下的单例对象
		beanFactory.preInstantiateSingletons();

具体讲解,我会单独拿出来说明。。。

1.5.1、下面我们结合一个FactoryBean接口的使用,分析一下FactoryBeanBeanFactory 的区别

package com.qzk.QzkFactoryBeanDir;

/**
 * @ClassName Car
 * @Description 汽车实现类
 * @Author qzk
 * @Date 2022/5/9 11:30 上午
 * @Version 1.0
 **/
public class Car {

    /**
     * 名称
     */
    private String name;

    /**
     * 品牌
     */
    private String brand;

    /**
     * 速度
     */
    private Integer speed;

    public Car() {
    }

    public Car(String name, String brand, Integer speed) {
        this.name = name;
        this.brand = brand;
        this.speed = speed;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public Integer getSpeed() {
        return speed;
    }

    public void setSpeed(Integer speed) {
        this.speed = speed;
    }

    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                ", brand='" + brand + '\'' +
                ", speed='" + speed + '\'' +
                '}';
    }
}

package com.qzk.QzkFactoryBeanDir;

import org.springframework.beans.factory.FactoryBean;

/**
 * @ClassName CarFactoryBean
 * @Description 实现了 FactoryBean 接口的 CarFactoryBean 汽车工厂
 * @Author qzk
 * @Date 2022/5/9 11:29 上午
 * @Version 1.0
 **/
public class CarFactoryBean implements FactoryBean<Car> {


    private String carInfo;

    public CarFactoryBean(String carInfo) {
        this.carInfo = carInfo;
    }

    public String getCarInfo() {
        return carInfo;
    }

    public void setCarInfo(String carInfo) {
        this.carInfo = carInfo;
    }

    @Override
    public Car getObject() throws Exception {
        Car car = new Car();
        String[] splits = carInfo.split(",");
        car.setName(splits[0]);
        car.setBrand(splits[1]);
        car.setSpeed(Integer.valueOf(splits[2]));
        return car;
    }

    @Override
    public Class<?> getObjectType() {
        return Car.class;
    }

    @Override
    public boolean isSingleton() {
        return FactoryBean.super.isSingleton();
    }
}

<?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">

    <!--  直接创建car1 这个bean   -->
    <bean id="car1" class="com.qzk.QzkFactoryBeanDir.Car" >
        <constructor-arg name="brand" value="奔驰"></constructor-arg>
        <constructor-arg name="name" value="E300"></constructor-arg>
        <constructor-arg name="speed" value="200"></constructor-arg>
    </bean>

    <!-- 利用无参构造, 结合 property 属性赋值的方式创建bean   -->
    <bean id="car2" class="com.qzk.QzkFactoryBeanDir.CarFactoryBean" >
        <property name="carInfo" value="总裁,玛莎拉蒂,251"></property>
    </bean>

    <!--  利用有参构造 结合 constructor-arg 参数传递的方式创建bean -->
    <bean id="car3" class="com.qzk.QzkFactoryBeanDir.CarFactoryBean">
        <constructor-arg name="carInfo" value="卡宴,保时捷,250"></constructor-arg>
    </bean>

</beans>
package com.qzk.QzkFactoryBeanDir;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @ClassName TestFactoryBean
 * @Description 测试 实现了FactoryBean接口的测试类
 * @Author qzk
 * @Date 2022/5/9 11:51 上午
 * @Version 1.0
 **/
public class TestFactoryBean {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("testFactoryBean.xml");
        Car car = (Car) context.getBean("car1");
        System.out.println(car); // Car{name='E300', brand='奔驰', speed='200'}
        Car car2 = (Car)context.getBean("car2");
        System.out.println(car2); // Car{name='总裁', brand='玛莎拉蒂', speed='251'}
        CarFactoryBean  bean = (CarFactoryBean) context.getBean("&car2");
        System.out.println(bean); // com.qzk.QzkFactoryBeanDir.CarFactoryBean@1d29cf23
        CarFactoryBean carFactoryBean = context.getBean("&car2",CarFactoryBean.class);
        System.out.println(carFactoryBean); // com.qzk.QzkFactoryBeanDir.CarFactoryBean@1d29cf23
        Car car21 = context.getBean("car2", Car.class);
        System.out.println("car2 是单例模式, 所以再工厂bean中获取的car2 应该是同一个bean,所以相同:" +(car21 == car2));
        Car car3 = (Car) context.getBean("car3");
        System.out.println(car3);
        Object car31 = context.getBean("car3");
        System.out.println("car3 是原型模式,所以这边应该是不等的:"+ (car31 == car3));
//
    }
}

image-20220509135451895

1.5.2、源码分析beanFactory.preInstantiateSingletons()

我们在上面的xml中分别定义个 car1 & car2 & car3,同样,spring 在读取的时候, 也会按照这个顺序依次去创建car

  1. 创建car1 普通bean 的执行流程

image-20220509140343972

大致的一个 bean创建流程 遵循如下如所示:

image-20220509140750733

在 执行doCreateBean 的过程中, 会根据 bean的类型, bean的定义信息(是否单例,是否原型, 是否懒加载, 是否初始化, 之类的信息, 做一些相关的处理工作,),并且会判断是否是工厂类, 以及是否是静态工厂,以及实例工厂等方式去执行不同的实例化步骤。

标签:01,String,beanFactory,Car,finishBeanFactoryInitialization,bean,speed,public
来源: https://www.cnblogs.com/qianzhengkai/p/16257658.html