到目前为止,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
事件驱动的加载执行过程;接下来开始解析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(); }
除了beanFactory.preInstantiateSingletons()
方法,其他都是Bean
创建的准备,接下来一个一个分析,首先是转换服务的设置。
方法一开始设置了一个转换服务,这个转换服务在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提供了,非常贴心。
那么怎么使用呢?
不懂当然是上官网: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
进行处理,当然也可以对属性值进行处理。
分析完值解析器,继续往下分析。
// 省略代码..... // 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
。