1. 程式人生 > 其它 >Spring原始碼分析之ConversionService

Spring原始碼分析之ConversionService

前言

ConversionService表示型別轉換服務,如將字串轉換為Long,字串轉換為日期等。在處理屬性和建立Bean物件等很多場景都會使用到。

ConversionService

相關類圖如下

預設實現為DefaultConversionService,預設增加了很多型別轉換器,如字串轉為集合。

import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;

public class Client {

  public static void main(String[] args) {
    ConversionService sharedInstance = DefaultConversionService.getSharedInstance();
    System.out.println(sharedInstance);//檢視所有Converter
    System.out.println(sharedInstance.canConvert(String.class, Integer.class));
    System.out.println(sharedInstance.convert("123", Integer.class));
  }

}

DefaultConversionService使用雙重鎖判斷來實現單例,不僅實現了ConversionService介面(型別轉換),,也實現了ConverterRegistry介面(登錄檔,可以增加轉化器)。

配置自定義型別轉換器

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.DefaultConversionService;

public class TestCustomConverter {

  public static void main(String[] args) {
    DefaultConversionService sharedInstance = (DefaultConversionService) DefaultConversionService
        .getSharedInstance();
    sharedInstance.addConverter(new StringToUserConverter());
    User user = sharedInstance.convert("lisi", User.class);
    System.out.println(user);//TestCustomConverter.User(name=lisi)
  }


  @Getter
  @Setter
  @ToString
  @AllArgsConstructor
  @NoArgsConstructor
  public static class User {

    private String name;
  }

  public static class StringToUserConverter implements Converter<String, User> {

    @Override
    public User convert(String source) {
      return new User(source);
    }
  }

}

自定義型別轉換器需要實現Converter介面,第一個泛型表示源型別,第二個表示目標型別。

Spring中配置ConversionService

import java.util.HashSet;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ConversionServiceFactoryBean;

@Configuration
public class BeanConfig {

  @Bean("conversionService")
  public ConversionServiceFactoryBean conversionServiceFactoryBean() {
    ConversionServiceFactoryBean factoryBean = new ConversionServiceFactoryBean();
    //可以在這裡新增自定義型別轉換器
    factoryBean.setConverters(new HashSet<>());
    return factoryBean;
  }
}

使用JavaConfig的方式來配置Bean,ConversionServiceFactoryBean底層實現也是DefaultConversionService。

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.convert.ConversionService;

public class TestConversionServiceConfig {

  public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
        BeanConfig.class);
    ConversionService conversionService = context.getBeanFactory().getConversionService();
    System.out.println(conversionService.convert("123", Integer.class));//123
  }
}

注意配置的ConversionServiceFactoryBean的Bean名稱必須為conversionService,這是因為BeanFactory會查詢型別為ConversionService且名稱為conversionService的Bean。

SpringBoot配置自定義Converter

SpringBoot會自動配置ConversionService物件,實現類為ApplicationConversionService(包含更多的型別轉換器)。

import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

  @Override
  public void addFormatters(FormatterRegistry registry) {
    registry.addConverter(new StringToUserConverter());
  }
}

SpringBoot也會將所有實現Converter介面的Bean新增到ConverterRegistry。