Spring 核心方法 refresh 刷新流程简要概述及相关源码扩展实现(二)(下)

简介: Spring 核心方法 refresh 刷新流程简要概述及相关源码扩展实现(二)(下)

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 属性,属性值可以实现任何 ConverterConverterFactoryGenericConverter接口

例如:需求,需要将一个字符串转换为一个具体的对象,如 “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 个人博客


目录
相关文章
|
3天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
14 2
|
19天前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
9天前
|
前端开发 Java 开发者
Spring生态学习路径与源码深度探讨
【11月更文挑战第13天】Spring框架作为Java企业级开发中的核心框架,其丰富的生态系统和强大的功能吸引了无数开发者的关注。学习Spring生态不仅仅是掌握Spring Framework本身,更需要深入理解其周边组件和工具,以及源码的底层实现逻辑。本文将从Spring生态的学习路径入手,详细探讨如何系统地学习Spring,并深入解析各个重点的底层实现逻辑。
35 9
|
1月前
|
Java Spring
Spring底层架构源码解析(三)
Spring底层架构源码解析(三)
108 5
|
1月前
|
XML Java 数据格式
Spring底层架构源码解析(二)
Spring底层架构源码解析(二)
|
Java 程序员 网络安全
spring4.1.8扩展实战之二:Aware接口揭秘
Aware.java是个没有定义任何方法的接口,拥有众多子接口,在spring源码中有多处都在使用这些子接口完成各种场景下的回调操作,当业务有需要时,我们只需创建类来实现相关接口,再声明为bean,就可以被spring容器主动回调
275 0
spring4.1.8扩展实战之二:Aware接口揭秘
|
2月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
1月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
162 2
|
8天前
|
缓存 IDE Java
SpringBoot入门(7)- 配置热部署devtools工具
SpringBoot入门(7)- 配置热部署devtools工具
19 2
 SpringBoot入门(7)- 配置热部署devtools工具
|
4天前
|
存储 运维 安全
Spring运维之boot项目多环境(yaml 多文件 proerties)及分组管理与开发控制
通过以上措施,可以保证Spring Boot项目的配置管理在专业水准上,并且易于维护和管理,符合搜索引擎收录标准。
15 2