• Spring 源码(9)Spring Bean的创建过程的前期准备


    回顾总结

    到目前为止,Spring源码中AbstractApplicationContext#refresh方法的已经解读到第11个方法finishBeanFactoryInitialization,前10个方法介绍了:

    • BeanFactory的准备,创建,刷新,个性化BeanFactory的扩展点,自定义属性解析;
    • 环境信息Environment的加载(包括环境变量、系统变量等);
    • BeanDefinition的加载,解析,自定义xml的方式;
    • BeanFactoryPostProcessor的注册与执行流程,BeanDefinitionRegistryPostProcessor的解析,ConfigurationClassPostProcessorSpring注解的解析过程(@Component、@PropertySources、@PropertySource、@ComponentScans、@ComponentScan、@Import等注解的解析),Spring Boot 是如何通过@Configuration+@Import + ImportSelector进行自动装配的等;
    • BeanPostProcessor的注册流程;
    • 国际化,Spring事件驱动的加载执行过程;

    finishBeanFactoryInitialization 解析过程

    接下来开始解析SpringBean的创建过程,上源码:

    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory 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));
      }
    
      // Register a default embedded value resolver if no BeanFactoryPostProcessor
      // (such as a PropertySourcesPlaceholderConfigurer bean) registered any before:
      // at this point, primarily for resolution in annotation attribute values.
      // 如果之前没有注册过任何 BeanFactoryPostProcessor(例如 PropertySourcesPlaceholderConfigurer bean),
      // 则注册一个默认的嵌入值解析器:此时,主要用于解析注释属性值。
      if (!beanFactory.hasEmbeddedValueResolver()) {
        beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
      }
    
      // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
      String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
      for (String weaverAwareName : weaverAwareNames) {
        getBean(weaverAwareName);
      }
    
      // Stop using the temporary ClassLoader for type matching.
      beanFactory.setTempClassLoader(null);
    
      // Allow for caching all bean definition metadata, not expecting further changes.
      // 允许缓存所有 bean 定义元数据,而不是期望进一步的更改
      beanFactory.freezeConfiguration();
    
      // Instantiate all remaining (non-lazy-init) singletons.
      // 实例化所有剩余的(非惰性初始化)单例
      beanFactory.preInstantiateSingletons();
    }
    
    • 判断是否存在转换服务,有就设置
    • 判断是否有内置的值解析器,没有就创建一个处理占位符的解析器
    • 实例化LoadTimeWeaverAware,进行早期的Bean的创建
    • 停止使用临时的类加载器
    • 冻结BeanDefinition的元数据信息,防止被修改
    • 开始实例化所有的单例bean对象

    除了beanFactory.preInstantiateSingletons() 方法,其他都是Bean创建的准备,接下来一个一个分析,首先是转换服务的设置。

    转换服务ConversionService的初始化

    方法一开始设置了一个转换服务,这个转换服务在Spring中还是非常的重要的,比如我们xml中配置一个String 类型的属性值,但是在Bean的定义中是一个Integer类型的,这时Spring就会自动帮我们转出来,他是怎么做的呢?

    Spring中有几个比较重要的接口:

    • Converer 用于将对象S转换为对象T
    • ConverterFactory 一个转换工厂,能够将对象S转成一类对象R的子集T,比如可以将字符串S转换为TInteger、Long等)Number类型R的子集
    • GenericConverter支持多种类型之间互相转换。

    Spring转换器接口ConversionService 的默认实现是DefaultConversionService,这个默认的转换器实现中,内置了很多的转换器,比如:

    public static void addDefaultConverters(ConverterRegistry converterRegistry) {
      addScalarConverters(converterRegistry);
      addCollectionConverters(converterRegistry);
    
      converterRegistry.addConverter(new ByteBufferConverter((ConversionService) converterRegistry));
      converterRegistry.addConverter(new StringToTimeZoneConverter());
      converterRegistry.addConverter(new ZoneIdToTimeZoneConverter());
      converterRegistry.addConverter(new ZonedDateTimeToCalendarConverter());
    
      converterRegistry.addConverter(new ObjectToObjectConverter());
      converterRegistry.addConverter(new IdToEntityConverter((ConversionService) converterRegistry));
      converterRegistry.addConverter(new FallbackObjectToStringConverter());
      converterRegistry.addConverter(new ObjectToOptionalConverter((ConversionService) converterRegistry));
    }
    
    public static void addCollectionConverters(ConverterRegistry converterRegistry) {
      ConversionService conversionService = (ConversionService) converterRegistry;
      // 数组转集合
      converterRegistry.addConverter(new ArrayToCollectionConverter(conversionService));
      // 集合转数组
      converterRegistry.addConverter(new CollectionToArrayConverter(conversionService));
    
      converterRegistry.addConverter(new ArrayToArrayConverter(conversionService));
      converterRegistry.addConverter(new CollectionToCollectionConverter(conversionService));
      converterRegistry.addConverter(new MapToMapConverter(conversionService));
      // 数组转字符串
      converterRegistry.addConverter(new ArrayToStringConverter(conversionService));
      converterRegistry.addConverter(new StringToArrayConverter(conversionService));
    
      converterRegistry.addConverter(new ArrayToObjectConverter(conversionService));
      converterRegistry.addConverter(new ObjectToArrayConverter(conversionService));
    
      converterRegistry.addConverter(new CollectionToStringConverter(conversionService));
      converterRegistry.addConverter(new StringToCollectionConverter(conversionService));
    
      converterRegistry.addConverter(new CollectionToObjectConverter(conversionService));
      converterRegistry.addConverter(new ObjectToCollectionConverter(conversionService));
    
      converterRegistry.addConverter(new StreamConverter(conversionService));
    }
    
    private static void addScalarConverters(ConverterRegistry converterRegistry) {
      converterRegistry.addConverterFactory(new NumberToNumberConverterFactory());
    
      converterRegistry.addConverterFactory(new StringToNumberConverterFactory());
      converterRegistry.addConverter(Number.class, String.class, new ObjectToStringConverter());
    
      converterRegistry.addConverter(new StringToCharacterConverter());
      converterRegistry.addConverter(Character.class, String.class, new ObjectToStringConverter());
    
      converterRegistry.addConverter(new NumberToCharacterConverter());
      converterRegistry.addConverterFactory(new CharacterToNumberFactory());
    
      converterRegistry.addConverter(new StringToBooleanConverter());
      converterRegistry.addConverter(Boolean.class, String.class, new ObjectToStringConverter());
    
      converterRegistry.addConverterFactory(new StringToEnumConverterFactory());
      converterRegistry.addConverter(new EnumToStringConverter((ConversionService) converterRegistry));
    
      converterRegistry.addConverterFactory(new IntegerToEnumConverterFactory());
      converterRegistry.addConverter(new EnumToIntegerConverter((ConversionService) converterRegistry));
    
      converterRegistry.addConverter(new StringToLocaleConverter());
      converterRegistry.addConverter(Locale.class, String.class, new ObjectToStringConverter());
    
      converterRegistry.addConverter(new StringToCharsetConverter());
      converterRegistry.addConverter(Charset.class, String.class, new ObjectToStringConverter());
    
      converterRegistry.addConverter(new StringToCurrencyConverter());
      converterRegistry.addConverter(Currency.class, String.class, new ObjectToStringConverter());
    
      converterRegistry.addConverter(new StringToPropertiesConverter());
      converterRegistry.addConverter(new PropertiesToStringConverter());
    
      converterRegistry.addConverter(new StringToUUIDConverter());
      converterRegistry.addConverter(UUID.class, String.class, new ObjectToStringConverter());
    }
    

    可以说是非常的丰富的,基本上常见都是Spring提供了,非常贴心。

    那么怎么使用呢?

    不懂当然是上官网:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#core-convert ,这里可以看到我们只需要将ConversionServiceFactoryBean 配置到Spring容器中就可以了,Spring内置的转换器就可以工作了,非常方便。

    ConversionServiceFactoryBean实现了FactoryBean接口和InitializingBean 接口,而InitializingBean#afterPropertiesSet是初始化Bean过程中需要执行的。ConversionServiceFactoryBean源码中:

    @Override
    public void afterPropertiesSet() {
      this.conversionService = createConversionService();
      ConversionServiceFactory.registerConverters(this.converters, this.conversionService);
    }
    
    protected GenericConversionService createConversionService() {
      return new DefaultConversionService();
    }
    
    // 构造函数
    public DefaultConversionService() {
      // 添加默认的转换器
      addDefaultConverters(this);
    }
    

    可以看到这个ConversionServiceFactroyBean就是用来初始化转换器的,并且这个类还提供了扩展,可以自定义转换器加入到转换器集合中。

    自定义转换器

    自定义String转Integer类型的转换器:

    /**
     * @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a>
     * @since 1.0
     **/
    public class StringToIntegerConverter implements Converter<String,Integer> , ConditionalConverter {
    	@Override
    	public Integer convert(String source) {
    		return NumberUtils.parseNumber(source,Integer.class);
    	}
    
    	@Override
    	public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
    		System.out.println(sourceType.getType());
    		System.out.println(targetType.getType());
    		return true;
    	}
    }
    

    逻辑非常简单,直接调用Spring提供的工具类进行转换。

    配置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"
    	   xmlns:context="http://www.springframework.org/schema/context"
    	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    
    	<context:component-scan base-package="com.redwinter.selfconverter"/>
    	<!--配置转化器-->
    	<bean class="org.springframework.context.support.ConversionServiceFactoryBean">
    		<property name="converters">
    			<set>
    				<bean class="com.redwinter.selfconverter.StringToIntegerConverter"/>
    			</set>
    		</property>
    	</bean>
    
    </beans>
    

    创建转换器客户端:

    /**
     * @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a>
     * @since 1.0
     **/
    @Service
    public class MyConverter {
    
    	private final ConversionService conversionService;
    
    	public MyConverter(ConversionService conversionService) {
    		this.conversionService = conversionService;
    	}
    
    	public void test(String source){
    		System.out.println(conversionService.convert(source, Integer.class));
    	}
    }
    

    创建测试:

    /**
     * @author <a href="2360564660@qq.com">redwinter</a>
     * @since 1.0
     **/
    public class FactoryBeanTest {
    
    	@Test
    	public void test(){
    		MyClassPathXmlApplicationContext context = new MyClassPathXmlApplicationContext("spring-factory.xml");
    		MyConverter myConverter = context.getBean(MyConverter.class);
    		myConverter.test("12345");
    	}
    }
    

    输出:

    class java.lang.String
    class java.lang.Integer
    12345
    

    分析完转换服务,接下来分析 值解析器的添加。

    默认的值解析器

    // 省略代码.....
    // Register a default embedded value resolver if no BeanFactoryPostProcessor
    // (such as a PropertySourcesPlaceholderConfigurer bean) registered any before:
    // at this point, primarily for resolution in annotation attribute values.
    // 如果之前没有注册过任何 BeanFactoryPostProcessor(例如 PropertySourcesPlaceholderConfigurer bean),
    // 则注册一个默认的嵌入值解析器:此时,主要用于解析注释属性值。
    if (!beanFactory.hasEmbeddedValueResolver()) {
      beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
    }
    // 省略代码.....
    
    
    

    首先判断了容器中是否存在嵌入的值解析器,如果没有就添加一个进去,这里添加进去的是StringValueResolver,点击resolvePlaceHolders方法进去,最终会在AbstractPropertyResolver#resolvePlaceholders中创建一个PropertyPlaceholderHelper

    private PropertyPlaceholderHelper createPlaceholderHelper(boolean ignoreUnresolvablePlaceholders) {
      // 前缀为 ${ ,后缀为 },值的分隔符为 : ,比如 ${username:zhansan} username没有的话,后面的为默认的值
      return new PropertyPlaceholderHelper(this.placeholderPrefix, this.placeholderSuffix,
                                           this.valueSeparator, ignoreUnresolvablePlaceholders);
    }
    

    如果已经注册过一个BFPP的占位符解析器的话,就不需要在注册了,BFPP的占位符解析器就是PropertySourcesPlaceholderConfigurer ,专门用于解析占位符的,比如在xml中或者yaml中,配置类似于${jdbc.username} 这种格式的,就会被解析器解析。PropertySourcesPlaceholderConfigurer 这个解析器实现了BeanFactoryPostProcessor接口,能够对BeanDefinition进行处理,当然也可以对属性值进行处理。

    分析完值解析器,继续往下分析。

    Bean创建前的其他准备

    // 省略代码.....
    // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
    // 在prepareBeanFactory 准备BeanFactory时设置进去的,如果存在,则开始早期Bean的创建
    String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
    for (String weaverAwareName : weaverAwareNames) {
      getBean(weaverAwareName);
    }
    
    // Stop using the temporary ClassLoader for type matching.
    // 停止使用临时的类加载器,这里也是在准备BeanFactory时设置进去的
    beanFactory.setTempClassLoader(null);
    
    // Allow for caching all bean definition metadata, not expecting further changes.
    // 允许缓存所有 bean 定义元数据,而不是期望进一步的更改
    beanFactory.freezeConfiguration();
    // 省略代码.....
    

    这里从容器中获取了AOP的织入,如果有的话就开始进行早期的Bean的创建;然后停止了临时的类加载器;然后就是冻结BeanDefinition的元数据信息。

    public void freezeConfiguration() {
      this.configurationFrozen = true;
      this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames);
    }
    

    点击进来,其实就是设置了标识,防止后期对BeanDefinition的修改。

    这前面的几个判断和方法实际上都是Bean创建的准备工作,接下来开始分析preInstantiateSingletons 预实例化所有的单例Bean

  • 相关阅读:
    JavaScript获取DOM元素相关信息和属性
    suricata学习记录
    智能咖啡厅助手:人形机器人 +融合大模型,行为驱动的智能咖啡厅机器人
    超级简单的SSM框架(全注解,源码+分析,看一眼就会)
    图解java.util.concurrent并发包源码系列——深入理解ConcurrentHashMap并发容器,看完薪水涨一千
    【汇编语言03】第2章 寄存器——实验1:查看CPU和内存,用机器指令和汇编指令编程
    js游戏集合
    面向切面:AOP
    【unity小技巧】unity事件系统创建通用的对象交互的功能
    鸿蒙Harmony应用开发—ArkTS声明式开发(拖拽事件)
  • 原文地址:https://www.cnblogs.com/redwinter/p/16241328.html