2022-08-23  阅读(42)
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://www.skjava.com/series/article/1832736547

在上篇文章中小编分析了 Spring ConversionService 类型转换体系,相信各位都对其有了一个清晰的认识,这篇博客将利用 ConversionService 体系来实现自己的类型转换器。

ConversionService 是 Spring 类型转换器体系中的核心接口,它定义了是否可以完成转换(canConvert()) 与 类型转换(convert())两类接口。ConversionService 有三个子类,每个子类针对不同的类型转换:

  • Converter<S,T>:将 S 类型对象转为 T 类型对象。
  • GenericConverter:会根据源类对象及目标类对象所在的宿主类中的上下文信息进行类型转换。
  • ConverterFactory:将相同系列多个 “同质” Converter 封装在一起。如果希望将一种类型的对象转换为另一种类型及其子类的对象(例如将 String 转换为 Number 及 Number 子类(Integer、Long、Double 等)对象)可使用该转换器工厂类。

如何自定义类型转换器?分两步走:

  1. 实现 Converter / GenericConverter / ConverterFactory 接口
  2. 将该类注册到 ConversionServiceFactoryBean 中。

ConversionServiceFactoryBean 实现了 InitializingBean 接口实现 afterPropertiesSet() ,我们知道在 Bean 实例化 bean 阶段,Spring 容器会检查当前 bean 是否实现了 InitializingBean 接口,如果是则执行相应的初始化方法。(关于 InitializingBean 详情请参考:【死磕 Spring】----- IOC 之 深入分析 InitializingBean 和 init-method)。afterPropertiesSet() 源码如下:

            public void afterPropertiesSet() {
             this.conversionService = createConversionService();
             ConversionServiceFactory.registerConverters(this.converters, this.conversionService);
            }

首先调用 createConversionService() 初始化 conversionService,然后调用 ConversionServiceFactory.registerConverters() 将定义的 converters 注入到类型转换体系中。createConversionService() 其实就是创建一个 DefaultConversionService 实例对象,对于 DefaultConversionService 小编在上篇博客已经分析了,如有不了解的请移步上篇博文。这里直接分析 ConversionServiceFactory.registerConverters(),该方法是将定义的 converter 注册到目标 ConverterRegistry 中,我们知道 ConverterRegistry 是一个 Converter 注册器,他定义了一系列注册方法。

             public static void registerConverters(@Nullable Set<?> converters, ConverterRegistry registry) {
              if (converters != null) {
               for (Object converter : converters) {
                if (converter instanceof GenericConverter) {
                 registry.addConverter((GenericConverter) converter);
                }
                else if (converter instanceof Converter<?, ?>) {
                 registry.addConverter((Converter<?, ?>) converter);
                }
                else if (converter instanceof ConverterFactory<?, ?>) {
                 registry.addConverterFactory((ConverterFactory<?, ?>) converter);
                }
                else {
                 throw new IllegalArgumentException("Each converter object must implement one of the " +
                   "Converter, ConverterFactory, or GenericConverter interfaces");
                }
               }
              }
             }

调用 ConverterRegistry 的 addConverter() 方法将转换器注册到容器中。所以在我们使用 Spring 容器的时候,Spring 将会自动识别出 IOC 容器中注册的 ConversionService 并且在 bean 属性注入阶段使用自定义的转换器完成属性的转换了。

实例

定义 StudentConversionService 转换器:

            public class StudentConversionService implements Converter<String,StudentService>{
            
                @Override
                public StudentService convert(String source) {
                    if(StringUtils.hasLength(source)){
                        String[] sources = source.split("#");
            
                        StudentService studentService = new StudentService();
                        studentService.setAge(Integer.parseInt(sources[0]));
                        studentService.setName(sources[1]);
            
                        return studentService;
                    }
                    return null;
                }
            }

配置:

            <bean id="conversionService"
                      class="org.springframework.context.support.ConversionServiceFactoryBean">
                <property name="converters">
                    <set>
                        <ref bean="studentConversionService"/>
                    </set>
                 </property>
             </bean>
            
            <bean id="studentConversionService" class="org.springframework.core.conversion.StudentConversionService"/>
            
            <bean id="student" class="org.springframework.core.conversion.Student">
                <property name="studentService" value="18#chenssy"/>
            </bean>

Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。

它的内容包括:

  • 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
  • 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
  • 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
  • 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
  • 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
  • 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
  • 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
  • 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw

目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:

想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询

同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。

阅读全文