返回顶部
首页 > 资讯 > 前端开发 > node.js >如何理解Spring的Registrar倒排思想
  • 329
分享到

如何理解Spring的Registrar倒排思想

2024-04-02 19:04:59 329人浏览 薄情痞子
摘要

这篇文章主要介绍“如何理解spring的ReGIStrar倒排思想”,在日常操作中,相信很多人在如何理解Spring的Registrar倒排思想问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,

这篇文章主要介绍“如何理解spring的ReGIStrar倒排思想”,在日常操作中,相信很多人在如何理解Spring的Registrar倒排思想问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何理解Spring的Registrar倒排思想”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

本文提纲

如何理解Spring的Registrar倒排思想

版本约定

正文

上文是通过手动调用api的方式实现元数据的解析从而达到数据格式化(转换)的目的,而在实际应用场景中,作为业务开发者是不可能去直接去操纵API的,毕竟说到底那对开发者太不友好,使用门槛过高。

因此,本文将介绍的是一种更为“高级”的使用方案,看看Spring是如何做到兼具高扩展性的整合,从而对开发者十分友好,相信这便也是Spring最有魅力的地方,一起来学习学习吧。

FormatterRegistry:注册中心

对于多组件的管理,注册中心是个很好的解决方案。

FORMatterRegistry其实在:9. 细节见真章,Formatter注册中心的设计很讨巧  这篇文章已经有过很详细的分析,学到了它那非常巧妙的设计,这里也顺道推荐你花几分钟前往看看。在这篇文章的末尾,A哥故意留下了一个小尾巴没讲:注册中心对注解工厂AnnotationFormatterFactory的支持,也就是这个接口方法:

FormatterRegistry:   void addFormatterForFieldAnnotation(AnnotationFormatterFactory<? extends Annotation> annotationFormatterFactory);

现在时机成熟,本文就来重点关照它。

该接口方法的唯一实现在FormattinGConversionService里:

如何理解Spring的Registrar倒排思想

①:从AnnotationFormatterFactory的泛型类型中提取到注解类型。注意:若没有指定泛型(没有指定注解类型)就抛出异常②:该工厂类支持的类型们③:对于支持的每个类型,均注册一个Printer/Parser

重点在于步骤③,AnnotationPrinterConverter和AnnotationParserConverter均是一个ConditionalGenericConverter转换器,底层实现实际委托给AnnotationFormatterFactory去完成,所以说对AnnotationFormatterFactory的理解格外的重要,还好上篇文章对它已经做了详尽分析,点击这里电梯直达。

下面以AnnotationPrinterConverter为例观其源码

如何理解Spring的Registrar倒排思想

①:该转换器只负责将fieldType类型转换为String类型②:只有fieldType上标注有指定的这个注解,此转换器才会生效③:转换逻辑。这种缓存式处理逻辑很是常见,其实最核心的代码往往只有一句,本处就是它:this.annotationFormatterFactory.getPrinter(...)。获取到合适的Printer,然后适配为PrinterConverter从而完成最终的convert转换动作

❝说明:PrinterConverter和ParserConverter在本系列前面文章已介绍,相关内容可出门左拐在本系列内很容易找到❞AnnotationParserConverter的实现逻辑如出一辙,这里就不再啰嗦了。

FormattingConversionService它实现了FormatterRegistry接口的所有接口方法,但是它并未提供一些默认行为。换句话讲:实现了所有的组件注册/管理的能力,但并没有“帮你”注册任何组件,所以还不具备能够直接提供服务的条件,若要使用还需“人工干预”放些组件进去才行。

一般来讲,对于这种情况一般在外部再包一层  DefaultXXX来提供默认服务是一种对开发者十分友好的解决方案,Spring也是这么干的,下面来看看DefaultFormattingConversionService为我们默认注册了哪些基础组件,提供了哪些能力呢。

DefaultFormattingConversionService

默认的格式化器转换服务,该默认行为适用于大多数应用程序对格式化器、转换器的需求。

继承自FormattingConversionService,这个默认行为是为该实例而设计的,但为了方便使用,它对外暴露了其static静态方法aDDDefaultFormatters(),这个设计方式同DefaultConversionService暴露了静态方法addDefaultConverters()如出一辙。

默认注册了哪些组件?

对于一个默认的Service服务,最关心的当属它提供了哪些能力。换句话讲:它默认帮我们注册了哪些组件呢?

要回答这个问题可不能靠“背答案”,方式方法其实非常的简单,爬进去它的源码处一看便知:

如何理解Spring的Registrar倒排思想

①:虽然说本类(其实是父类)实现了EmbeddedValueResolverAware接口,但构造时依旧可以指定占位符处理器StringValueResolver,当然一般情况下传入null即可②:调用DefaultConversionService的静态方法,把默认的转换器们都注册进来。那么,默认到底注册了哪些转换器呢?DefaultConversionService.addDefaultConverters(this)该静态方法其实是本系列前面文章所讲的内容,这里A哥顺道也贴在这吧:

如何理解Spring的Registrar倒排思想

③:若registerDefaultFormatters为true就添加默认的格式化器们,一般来讲,此值都为true。那么,默认到底注册了哪些格式化器呢?

如何理解Spring的Registrar倒排思想

①:对@NumberFormat注解提供支持,格式化数字(Currency、数字、百分数等)

②:对jsR  354钱币类型javax.money.CurrencyUnit、Monetary等类型提供支持。一般情况下,用不着,所以此part不会被真的注册

③:对JSR-310日期时间的格式化提供支持。这里使用到了其专用的注册器DateTimeFormatterRegistrar统一操作

④、⑤:第4、5步是互斥操作,若有Jota-Time就提供对它的支持而不触发java.util.Date的注册器,否则使用后者注册器。

注意:你以为④、⑤是真的互斥吗?难道导入了joda-time的包后java.util.Date相关模块就失效了?很明显不是这样的,让你“放心”的地方在于JodaTimeFormatterRegistrar注册器内部包含了java.util.Date格式化器的注册关系,因此一切都还得到xxxRegistrar里去看才能揭晓。

总之,DefaultFormattingConversionService作为默认的格式化转换服务,它是DefaultConversionService的超集,在其基础上扩展了格式化器,格式化注解支持等相关能力。在Spring环境下,大多数情况使用都是它而非DefaultConversionService。

如何理解Spring的Registrar倒排思想

现在,对FormatterRegistry类一个笼统的认识,知道它默认给注册了哪些组件,支持哪些功能,但是细节部分还不清晰。比如说:支持哪些数据类型?支持哪些格式?这些都藏在相应的xxxRegistrar里~

FormatterRegistrar:注册员

registrar:登记员;注册主任。

xxxRegistrar它是一种“倒排”思想的设计体现,能达到高内聚的效果。Spring、Spring  Boot惯用的“伎俩”,譬如你随便一搜就能看能看到很多很多:

如何理解Spring的Registrar倒排思想

FormatterRegistrar代表的是格式化器注册员接口,接口定义:

public interface FormatterRegistrar {  void registerFormatters(FormatterRegistry registry); }

接口方法含义:将Converter和Formatter注册进FormatterRegistry注册中心里,至于注册哪些组件由各子类自行管理和负责,而非Registry注册中心主动去编排。这是一种倒排设计思想,能够很好的达到高内聚的目的。

❝注意:虽然存在ConverterRegistry和FormatterRegistry两个接口,但只有FormatterRegistrar而 没有  ConverterRegistrar哦❞该接口有三个实现类:

如何理解Spring的Registrar倒排思想

见名之意,每个实现子类都维护着自己分内之事,边界十分清晰。

DateFormatterRegistrar:Date注册员

提供对java.util.Date、java.util.Calendar、long类型的日期时间的注册支持。

接口方法实现如下:

如何理解Spring的Registrar倒排思想

①:添加常规转换器,支持DateToLong、DateToCalendar、LongToCalendar等基础转换能力②:若有个性化指定格式化器,那就给Calendar专门使用。当然,大多数情况下并不会这么做,这步逻辑是为了向后兼容性而考虑而已,一般可忽略③:添加@DateTimeFormat注解的解析支持

代码示例

下面介绍DateFormatterRegistrar注册员的使用示例。

普通使用方式

最常规的转换,Date、Long、Calendar等日期时间类型似乎是可以互转的。

@Test public void test1() {     FormattingConversionService conversionService = new FormattingConversionService();     // 注册员负责添加格式化器以支持Date系列的转换     new DateFormatterRegistrar().registerFormatters((FormatterRegistry) conversionService);      // 1、普通使用     long currMills = System.currentTimeMillis();     System.out.println("当前时间戳:" + currMills);     // Date -> Calendar     System.out.println(conversionService.convert(new Date(currMills), Calendar.class));     // Long ->  Date     System.out.println(conversionService.convert(currMills, Date.class));     // Calendar -> Long     Calendar calendar = Calendar.getInstance(TimeZone.getDefault());     calendar.setTimeInMillis(currMills);     System.out.println(conversionService.convert(calendar, Long.class)); }

运行程序,输出:

当前时间戳:1612741385457 java.util.GreGorianCalendar[time=1612741385457 ... Mon Feb 08 07:43:05 CST 2021 1612741385457

完美。

注解使用方式

使用更高级的注解方式,如@DateTimeFormat

// 准备一个Java Bean: @Data @AllArgsConstructor class Son {      @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)     private Date birthday;  }

测试代码:

@Test public void test1() {     FormattingConversionService conversionService = new FormattingConversionService();     // 重要:重要:重要:注册基础的转换能力     DefaultConversionService.addDefaultConverters((ConverterRegistry) conversionService);     // 注册员负责添加格式化器以支持Date系列的转换     new DateFormatterRegistrar().registerFormatters((FormatterRegistry) conversionService);      // 1、注解使用     Son son = new Son(new Date());     // 输出:将Date类型输出为Long类型     System.out.println(conversionService.convert(son.getBirthday(), Long.class));     // 输出:将String烈性输入为Date类型     // System.out.println(conversionService.convert("2021-02-12", Date.class)); // 报错     System.out.println(conversionService.convert(1613034123709L, Date.class)); }

运行程序,输出:

1613034230018 Thu Feb 11 17:02:03 CST 2021

完美。实现了Long类型 <-> Date类型的互转。

到此,关于“如何理解Spring的Registrar倒排思想”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: 如何理解Spring的Registrar倒排思想

本文链接: https://lsjlt.com/news/83645.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 如何理解Spring的Registrar倒排思想
    这篇文章主要介绍“如何理解Spring的Registrar倒排思想”,在日常操作中,相信很多人在如何理解Spring的Registrar倒排思想问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,...
    99+
    2024-04-02
  • 如何理解域名状态REGISTRAR-HOLD的含义
    这篇文章将为大家详细讲解有关如何理解域名状态REGISTRAR-HOLD的含义,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。域名状态REGISTRAR-HOLD的含义.REGISTRAR-H...
    99+
    2023-06-12
  • 如何理解Elasticsearch倒排索引与分词
    本篇内容主要讲解“如何理解Elasticsearch倒排索引与分词”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何理解Elasticsearch倒排索引与分词...
    99+
    2024-04-02
  • 如何理解“面向对象”编程思想
    理解面向对象,首先理解要它的基础概念: 面向对象是将现实问题构建关系,然后抽象成 类 ( class ) ,给类定义属性和方法后,再将类实例化成 实例 ( instance ) ,通过访问实例的属性和调用方法来进行使用。 在不同的语言中,...
    99+
    2023-01-30
    面向对象 思想
  • 如何站在开发者的角度理解框架的设计思想?
    感谢支持 我已经在CSDN发布了100多篇原创文章,如果你读过我的文章,欢迎点击下方的链接,帮我五星评价一下,谢谢。 很简单,点击下图,像截图一样五星评价一下就可以了: 有问必答 最近有好多读者...
    99+
    2023-10-11
    java 前端 数据库 golang 后端
  • 如何以go思想去处理js异常抛弃trycatch
    本篇内容主要讲解“如何以go思想去处理js异常抛弃trycatch”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何以go思想去处理js异常抛弃trycatch”吧!错误处理的方式通常情况下 错...
    99+
    2023-07-05
  • PHP MVC 架构的本质:理解框架背后的思想
    MVC(模型-视图-控制器)架构是一种被广泛应用于 Web 开发中的软件架构范式,它将应用程序逻辑清晰地分离为三个独立的组件:模型、视图和控制器。这种分离使得应用程序的可维护性、可测试性和可扩展性得到极大提升。 模型 模型负责管理应用程...
    99+
    2024-03-02
    MVC、PHP、框架设计、软件架构
  • 如何使用Vue的思想封装一个Storage
    目录背景功能目的想法来源实现setgetdeletePropertypreventExtensionshas总结背景 localStorage、sessionStorage 这两个...
    99+
    2024-04-02
  • 如何理解排序算法
    这篇文章主要讲解了“如何理解排序算法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何理解排序算法”吧!排序是我们生活中经常会面对的问题,体育课的时候,老师...
    99+
    2024-04-02
  • 如何使用Python中的函数式编程思想解决问题
    如何使用Python中的函数式编程思想解决问题引言:函数式编程是一种编程范式,它将计算视为数学函数的求值,并避免了状态和可变数据。Python是一种支持函数式编程的语言,在Python中,我们可以使用函数式编程思想解决许多常见的问题。本文将...
    99+
    2023-10-22
    函数式编程 问题解决 关键词:Python
  • sql语句查询性能的优化思想(个人理解)
    我对sql语句优化的理解,从以下四个方面入手:1.改写SQL;2.调整数据库或者系统的参数。3.调整表结构;4.建索引。 后续会继续完善的^-^ ...
    99+
    2024-04-02
  • 如何理解spring框架中的ioc
    这期内容当中小编将会给大家带来有关如何理解spring框架中的ioc,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。摘要: 关于spring框架中的ioc的幽默解释 IoC就是Inversion of Co...
    99+
    2023-06-17
  • 如何理解MySQL中filesort排序
    MySQL中什么是filesort排序,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。排序(filesort)作为DBA绕不开的话题,也经常...
    99+
    2024-04-02
  • 如何理解Spring的Hibernate事务管理机制
    如何理解Spring的Hibernate事务管理机制,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。主要讲了Spring 声明式事务让我们从复杂的Hibernate事务处理中...
    99+
    2023-06-17
  • 如何理解Spring AOP的实现机制
    这篇文章将为大家详细讲解有关如何理解Spring AOP的实现机制,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。AOP(Aspect Orient Programming),一般称为面向切面...
    99+
    2023-06-16
  • 如何理解Kubernetns容器与VM的编排
    这篇文章主要讲解了“如何理解Kubernetns容器与VM的编排”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何理解Kubernetns容器与VM的编排”...
    99+
    2024-04-02
  • 如何理解Spring双层事务
    这篇文章主要讲解了“如何理解Spring双层事务”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何理解Spring双层事务”吧!系统 A 调用系统 B 执行数据同步,系统 B 返回了错误提示...
    99+
    2023-06-15
  • Spring Boot 多数据源处理事务的思路详解
    目录1. 思路梳理2. 代码实践2.1 案例准备2.2 开始整活LoadDataSource.java3. 总结首先我先声明一点,本文单纯就是技术探讨,要从实际应用中来说的话,我并不...
    99+
    2024-04-02
  • 理解Java注解及Spring的@Autowired是如何实现的
    首先我们可以自己写一个注解: @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @in...
    99+
    2024-04-02
  • 如何理解MySQL的分页和排序技术?
    如何理解MySQL的分页和排序技术?概述:MySQL是一个广泛使用的关系型数据库管理系统,它提供了丰富的功能和技术,其中包括了分页和排序技术。分页技术可以用来显示大量数据的部分内容,而排序技术则可以对数据按照特定规则进行排序。在实际应用中,...
    99+
    2023-10-22
    分页 MySQL 排序
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作