ConversionService
序言
在读SpringBoot源码的时候,在springBoot启动过程中有一步环境配置,根据默认设置会实例化一个ConversionService实例,并且还是有点东西,主要是单例模型和用一个service来管理一堆转换器的思想,本文就来看看实例化过程。
ConversionService conversionService = ApplicationConversionService.getSharedInstance();
ConversionService
首先还是先回顾下什么是ConversionService:
ConversionService 是一个类型转换服务接口,并且还是线程安全的。看看接口的实现类有哪些。
ApplicationConversionService
代码中可以看到,此处实例化的是ApplicationConversionService,那就来看看ApplicationConversionService吧。
单例模式
很幸运在这里看到了一个单例模式的案例,还是懒汉模式:
/**
* 返回共享的默认应用程序ConversionService实例,并在需要时延迟构建它。
* 注意:此方法实际上返回一个ApplicationConversionService实例。 但是,保留了ConversionService签名以实现二进制兼容性。
* @return the shared {@code ApplicationConversionService} instance (never
* {@code null})
*/
public static ConversionService getSharedInstance() {
ApplicationConversionService sharedInstance = ApplicationConversionService.sharedInstance;
if (sharedInstance == null) {
synchronized (ApplicationConversionService.class) {
sharedInstance = ApplicationConversionService.sharedInstance;
if (sharedInstance == null) {
sharedInstance = new ApplicationConversionService();
ApplicationConversionService.sharedInstance = sharedInstance;
}
}
}
return sharedInstance;
}
单例的实现过程:
- 首先定义了一个static的ApplicationConversionService 对象:
private static volatile ApplicationConversionService sharedInstance;
- 然后每次获取实例的方式都是先看对象实例化没有;
- 如果没有实例化,加个类锁,防止多个线程同时来实例化这个单例。
- 重点,加锁后都还要看下这个对象有没有被实例化。
- 实例化对象。
我为什么要把这个单例实现代码拿来说呢,因为我们平时都没考虑到这个问题,为什么我加锁实例化的过程还是要去判空呢?
仔细想想,确实要这样,if (sharedInstance == null)
和synchronized (ApplicationConversionService.class)
这是两个原子操作,这点以往确实没想到过。
初始化
好了欣赏完单例模式的代码后,我们来看看ApplicationConversionService的实例化过程。
public ApplicationConversionService() {
this(null);
}
public ApplicationConversionService(StringValueResolver embeddedValueResolver) {
if (embeddedValueResolver != null) {
setEmbeddedValueResolver(embeddedValueResolver);
}
configure(this);
}
没啥看的,直接configure吧。
FormatterRegistry
ConverterRegistry
config过程
/**
*使用适合大多数Spring Boot应用程序的格式化程序和转换器配置给定的FormatterRegistry 。
* @param registry the registry of converters to add to (must also be castable to
* ConversionService, e.g. being a {@link ConfigurableConversionService})
* @throws ClassCastException if the given FormatterRegistry could not be cast to a
* ConversionService
*/
public static void configure(FormatterRegistry registry) {
//添加适用于大多数环境的转换器。
DefaultConversionService.addDefaultConverters(registry);
//添加适用于大多数环境的格式化程序:包括数字格式化程序,JSR-354货币和货币格式化程序,JSR-310日期时间格式化程序和/或Joda时间格式化程序,具体取决于类路径上相应API的存在。
DefaultFormattingConversionService.addDefaultFormatters(registry);
//添加对大多数Spring Boot应用程序有用的格式化程序。
addApplicationFormatters(registry);
//添加对大多数Spring Boot应用程序有用的转换器。
addApplicationConverters(registry);
}
我看了下,添加的大部分转换器和格式化程序的作用域都是包内,对于这个我想说6点……
好了,我也不去看代码了,直接看下结果吧:
134个转换器,不知道是干嘛的,咱也不敢问,先这样吧,接着往下看代码。