> 文档中心 > Spring 源码(9)Spring Bean的创建过程的前期准备

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


回顾总结

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

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

finishBeanFactoryInitialization 解析过程

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

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 转换为 T ( Integer、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提供了,非常贴心。

那么怎么使用呢?

不懂当然是上官网: Core Technologies ,这里可以看到我们只需要将 ConversionServiceFactoryBean 配置到Spring容器中就可以了, Spring 内置的转换器就可以工作了,非常方便。

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

@Overridepublic 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 redwinter * @since 1.0 **/public class StringToIntegerConverter implements Converter , ConditionalConverter {@Overridepublic Integer convert(String source) {return NumberUtils.parseNumber(source,Integer.class);}@Overridepublic boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {System.out.println(sourceType.getType());System.out.println(targetType.getType());return true;}}

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

配置xml:

创建转换器客户端:

/** * @author redwinter * @since 1.0 **/@Servicepublic 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 redwinter * @since 1.0 **/public class FactoryBeanTest {@Testpublic void test(){MyClassPathXmlApplicationContext context = new MyClassPathXmlApplicationContext("spring-factory.xml");MyConverter myConverter = context.getBean(MyConverter.class);myConverter.test("12345");}}

输出:

class java.lang.Stringclass java.lang.Integer12345

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

默认的值解析器

// 省略代码.....// 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 。