ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-05-11 14:01:18  阅读:208  来源: 互联网

标签:01 String beanFactory Car finishBeanFactoryInitialization bean speed public


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

正如截图中的注解所言:

  • LoadTimeWeaverAware 主要是在AOP中进行使用的, 后面我们讨论AOP的时候在进行补充

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

image-20220506233443960

这部分怎么理解呢?

  • 这部分主要是做实例化之前的禁止操作,实例化之前,我们不希望beanFactory中的bean定义信息BeanDefinition 再有修改。所以存在上述的一些操作

  • beanFactory.setTempClassLoader(null); 即 精致使用临时类加载器, 在进行类型匹配操作了,即不希望再有类的一些定义信息再加入到``beanFactory`了。

  • beanFactory.preInstantiateSingletons(); 即 冻结所有的BeanDefinition 定义, 说明注册的bean定义将不被修改或者任何进一步的处理。

    • 	public void freezeConfiguration() {
      		this.configurationFrozen = true;
      		this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames);
      	}
      
    • 这里主要做了两件事

      • 设置冻结的标志位
      • 将所有的冻结的BeanDefinitionNames 即bean定义信息的名称, 添加到frozenBeanDefinitionNames 字符串数组中去。

1.5、第五部分概述- preInstantiateSingletons

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

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

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

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

  • 实现一个Car 汽车类
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 + '\'' +
                '}';
    }
}

  • 实现一个继承FactoryBean接口的类,重写getObject() 方法,返回Car 对象。
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配置文件 testFactoryBean.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">

    <!--  直接创建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>
  • 编写测试启动类 TestFactoryBean
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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有