ConversionService 转换服务
转换服务:从一个类型到另外一个类型的转换,提前储备一些转换器,由具体的转换器来完成对应的转换操作
接口介绍
定义类型转换器依赖于以下比较重要的接口
public interface Converter<S, T> { /** * S 类型转换成 T 类型 */ @Nullable T convert(S source); }
Converter 接口:提供从源类型转换为目标类型的一个过程,具体的转换功能由其子类去实现,对于每次调用 convert(S),源对象参数保证不能为空,仅支持 1 ~ 1 类型之间的转换,例如 StringToInteger
public interface ConverterFactory<S, R> { /** * 获取转换器 */ <T extends R> Converter<S, T> getConverter(Class<T> targetType); }
ConverterFactory 接口:converter 转换器的工厂类,用来获取对应的转换器【源类型转换为继承于某类的多个子类】1 ~ n 的转换,从一个目标类可转换为一个基类下的多个派生类,例如:StringToEnumConverterFactory
public interface GenericConverter { /** * 返回转换器集合可以转换源和目标类型 */ @Nullable Set<ConvertiblePair> getConvertibleTypes(); /** * 转换源对象到目标类型的描述 * 源 TypeDescriptor 提供对保存正在转换的值的源字段的访问 * 目标 TypeDescriptor 提供对要设置转换值的目标字段的访问 */ @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType); } // 组建一个源到目的的组合 final class ConvertiblePair { private final Class<?> sourceType; private final Class<?> targetType; /** * 创建一个新的源-目标组合 */ public ConvertiblePair(Class<?> sourceType, Class<?> targetType) { Assert.notNull(sourceType, "Source type must not be null"); Assert.notNull(targetType, "Target type must not be null"); this.sourceType = sourceType; this.targetType = targetType; } public Class<?> getSourceType() { return this.sourceType; } public Class<?> getTargetType() { return this.targetType; } }
GenericConverter 接口:当您需要复杂 Converter 实现时,考虑使用这个接口,支持在多个源类型和目标类型之间进行转换,例如 ArrayToCollectionConverter
public interface ConditionalConverter { /** * 判断是否匹配能够从源类型转换为目标类型 */ boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType); }
ConditionalGenericConverter 接口:当您希望 Converter 只有在特定条件成立时才能允许,你可以希望仅在目标类上定义了特定方法才能进行转换,例如:ConditionalGenericConverter
public interface ConversionService { /** * 判断能否进行类型转换 */ boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType); boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType); /** * 类型转换,获取合适的转换器进行类型的转换,默认是 DefaultConversionService,也可以是自定义的 */ @Nullable <T> T convert(@Nullable Object source, Class<T> targetType); @Nullable Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType); }
ConversionService
:类型转换服务,用于在运行时执行类型转换的逻辑
大部分的 ConversionService 通常都实现了 ConverterRegistry【用于提供注册转换器】,ConversionService 实现委托其注册的转换器执行具体类型转换逻辑.
GenericConversionService 是 ConversionService 实现类,适用于大多数环境的通用实现
配置 ConversionService
默认值 ConversionService
可以在字符串、数字、枚举、集合、映射和其他常见类型之间进行转换,如果需要使用自定义转换器或覆盖默认转换器,需要设置 ConversionServiceFactoryBean#converters 属性,属性值可以实现任何 Converter
、ConverterFactory
或GenericConverter
接口
例如:需求,需要将一个字符串转换为一个具体的对象,如 “1_zhangsan_“ 设置为 Student 的 id 和 name 属性.
public class StudentConverter implements Converter<String,Student> { @Override public Student convert(String source) { System.out.println("-----"); Student s = new Student(); String[] splits = source.split("_"); s.setId(Integer.parseInt(splits[0])); s.setName(splits[1]); return s; } }
<!-- xml 方式配置 --> <bean id="studentConverter" class="com.mashibing.selfConverter.StudentConverter"/> <bean id ="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <set> <ref bean="studentConverter"/> </set> </property> </bean>
// 注解方式配置 @Configuration public class AppConfig { @Bean public ConversionService conversionService() { DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService(); conversionService.addConverter(new MyCustomConverter()); return conversionService; } }
ValueResolver 值处理器
<context:property-placeholder location="classpath:db.properties"/>
如果新增了以上标签,那么在解析以上自定义标签时,解析器 PropertyPlaceholderBeanDefinitionParser
会为我们新增对应的 org.springframework.context.support.PropertySourcesPlaceholderConfigurer 类的 BeanDefinition 进去,那么在调用 invokeBeanFactoryPostProcessors
时,同时 PropertySourcesPlaceholderConfigurer 实现了 BFPP 接口,那么就会调用 postProcessBeanFactory 方法【进行占位符变量的解析工作】,这时已经提前设置好了占位符处理器为内置的值处理器
如果没有配置以上自定义标签的话,那么 Spring 默认是不会配置的,那么在这边就会去做新增值处理器的一个操作.
织入、冻结
// 尽早初始化 loadTimeWeaverAware bean,以便尽早注册它们的转换器 String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); for (String weaverAwareName : weaverAwareNames) { getBean(weaverAwareName); } // 禁止使用临时类加载器进行类型匹配 beanFactory.setTempClassLoader(null); // 冻结所有 bean 定义,说明注册 bean 定义将不被修改或任何进一步的处理 beanFactory.freezeConfiguration(); // 实例化剩下的单例对象 beanFactory.preInstantiateSingletons();
LoadTimeWeaverAware 类是与 AOP 相关的
在准备实例化单例对象时即调用 preInstantiateSingletons
方法前,先把所有的 BeanDefinition 信息冻结起来,防止被修改和进一步的处理
preInstantiateSingletons
是实例化初始化 Bean 核心方法,后续单独整理一篇「Spring Bean 生命周期」文章进行详细介绍
finishRefresh
完成刷新过程,通知生命周期处理器 LifecycleProcessor 刷新过程,同时发出 ContextRefreshEvent 事件通知别人
protected void finishRefresh() { // 清除上下文级别的资源缓存(如扫描的 ASM 元数据) // 清空在资源加载器中的所有资源缓存 clearResourceCaches(); // 为这个上下文初始化生命周期处理器 // 初始化 LifecycleProcessor:如果上下文中找到'lifecycleProcessor' 的 LifecycleProcessor Bean 对象,则使用 DefaultLifecycleProcessor initLifecycleProcessor(); // 首先将刷新传播到生命周期处理器 // 上下文刷新的通知,例如自动启动的组件 getLifecycleProcessor().onRefresh(); // 发布最终事件 // 新建 ContextRefreshedEvent 事件对象,将其发布给所有监听器 publishEvent(new ContextRefreshedEvent(this)); // 参与 LiveBeansView MBean,如果是活动的 // LiveBeansView:Spring 用于支持JMX 服务的类 // 注册当前上下文到 LiveBeansView,以支持 JMX 服务 LiveBeansView.registerApplicationContext(this); }
在 SpringBoot 启动容器时对该方法也做了特殊的处理,代码如下:
protected void finishRefresh() { //调用父类 finishRefresh 方法 super.finishRefresh(); // 启动 webServer WebServer webServer = startWebServer(); if (webServer != null) { // 发布 webServer 初始化完成事件 publishEvent(new ServletWebServerInitializedEvent(webServer, this)); } }
resetCommonCaches
重置在 Spring 核心的内置缓存,因为我们可能不再需要单例 bean 元数据
protected void resetCommonCaches() { // 清除方法、属性缓存 ReflectionUtils.clearCache(); AnnotationUtils.clearCache(); // 清除对象映射、序列化包装对象缓存 ResolvableType.clearCache(); CachedIntrospectionResults.clearClassLoader(getClassLoader()); }
总结
至此,AbstractApplicationContext#refresh 方法中涉及到的 13 个方法简要已经分析完成了
编写文章不易,觉得可以帮助到你的内容,帮忙给个赞👍和关注,感谢🙏!!!
更多技术文章可以查看:vnjohn 个人博客