关于我们

使用@AutoConfigureBefore调整配置顺序竟没生效?

  

  一个人的价值体现在能够帮助多少人。自己编码好,价值能得到很好的体现。若你做出来的东西能够帮助别人开发,大大减少开发的时间,那就功德无量。

  各位小伙伴大家好,我是A哥。Spring Boot是Spring家族具有划时代意义的一款产品,它发展自Spring Framework却又高于它,这种高于主要表现在其最重要的三大特性,而相较于这三大特性中更为重要的便是Spring Boot的自动配置(AutoConfiguration)。与其说是自动,倒不如说是“智能”,该框架看起来好像“更聪明”了。因此它也顺理成章的成为了构建微服务的基础设施,稳坐第一宝座。

  生活之道,在于取舍。编程何尝不是,任何决定都会是一把双刃剑,Spring Boot的自动配置解决了Spring Framework使用起来的众多痛点,让开发效率可以得到指数级提升(想一想,这不就是功德无量吗?)。成也萧何败也萧何,也正是因为它的太智能,倘若出了问题就会让程序员两眼一抹黑,无从下手。

  本文将要聊的重点是Spring Boot自动配置 + 顺序控制,自动配置大家都耳熟能详,那么“首当其冲”就是知晓这个问题:配置类的执行为何需要控制顺序?

  我们已经知道Spring容器它对Bean的初始化是无序的,我们并不能想当然的通过@Order注解来控制其执行顺序。一般来说,对于容器内普通的Bean我们只需要关注依赖关系即可,而并不需要关心其绝对的顺序,而依赖关系的管理Spring的是做得很好的,这不连循环依赖它都可以搞定麽。

  @Configuration配置类它也是一个Bean,但对于配置类来说,某些场景下的执行顺序是必须的,是需要得到保证的。比如很典型的一个非A即B的case:若容器内已经存在A了,就不要再把B放进来。这种case即使用中文理解,就能知道对A的“判断”必须要放在B的前面,否则可能导致程序出问题。

  那么针对于配置的执行顺序,传统Spring和Spring Boot下各自是如何处理的,表现如何呢?

  在传统的Spring Framework里,一个@Configuration注解标注的类就代表一个配置类,当存在多个@Configuration时,他们的执行顺序是由使用者靠手动指定的,就像这样:

  当然,你可能就疑问了说:即使在传统Spirng里,我也从没有自己使用过AnnotationConfigApplicationContext来显示加载配置啊,都是使用@Configuration定义好配置类后,点击Run一把唆的。没错,那是因为你是在web环境下使用Spring,IoC容器是借助web容器(如Tomcat等)来驱动的,Spring对此部分封装得非常好,所以做到了对使用者几乎无感知。

  关于这部分的内容,此处就不深究了,毕竟本文重点不在这嘛。但可以给出给小结论:@Configuration配置被加载进容器的方式大体上可分为两种:

  绝大多数情况下我们都是使用自动的方式,所以在Spring下对配置的顺序并无感知。其实这也是需求驱使,因为在传统Spring下我们并无此需求,所以对它无感是合乎逻辑的。另说一句,虽然我们并不能控制Bean的顺序,但是我们是可以干涉它的,比如:控制依赖关系、提升优先级、“间接”控制执行顺序...当然喽这是后面文章的内容,敬请关注。

  Spring Boot下对自动配置的管理对比于Spring它就是黑盒,它会根据当前容器内的情况来动态的判断自动配置类的加载与否、以及加载的顺序,所以可以说:Spring Boot的自动配置它对顺序是有强要求的。需求驱使,Spring Boot给我们提供了@AutoConfigureBefore、@AutoConfigureAfter、@AutoConfigureOrder(下面统称这三个注解为“三大注解”)这三个注解来帮我们解决这种诉求。

  需要注意的是:三大注解是Spring Boot提供的而非Spring Framework。其中前两个是1.0.0就有了,@AutoConfigureOrder属于1.3.0版本新增,表示绝对顺序(数字越小,优先级越高)。另外,这几个注解并不互斥,可以同时标注在同一个@Configuration自动配置类上。

  为方便大家理解,我列出一个Spring Boot它自己的使用作为示例学一学。以大家最为熟悉的WebMvc的自动配置场景为例:

  在WebMvcAutoConfiguration加载后,在它之后其实还有很多配置会尝试执行,例如:

  根据我的切身体会,针对这三大注解,实在有太多人把它误用了,想用但是用了却又不生效,于是就容易触发一波“骂街”操作,其实这也是我书写本文的最大动力所在:纠正你的错误使用,告诉你正确姿势。

  通过名称能知道我想要的达到的效果是:ParentConfig先加载,SonConfig后加载。(DemoConfig作为一个参考配置,作为日志参考使用即可)

  Son优先于Parent被加载了,这明显不符合要求。因此,我看到很多小伙伴就这么干:

  通过@AutoConfigureBefore控制,表示在A_SonConfig之前执行此配置。语义层面上看,貌似没有任何问题,再次启动应用:

  竟然没生效?代码不会骗人,@AutoConfigureBefore的语义也没有问题,而是你使用的姿势不对,下面我会给你正确姿势。

  完美。符合预期,Parent终于在Son之前完成了初始化,也就是说我们的@AutoConfigureBefore注解生效了。

  针对此使用姿势,虽然很正确,并不是完全没有“副作用”的,有如下细节平时也需要引起注意:

  这个注解,单单就想依赖于spring.factories里的先后顺序的来控制实际的加载顺序,答案是

  来指定的,它的优先级最低(执行时机是最晚的);通过扫描进来的一般都是你自己自定义的配置类,所以优先级是最高的,

  这种包名,否则“天下大乱”(当然喽为了防止这种情况出现,Spring Boot做了容错的。它有一个类专门检测这个case防止你配置错了,具体参见

  小总结,对于三大注解的正确使用姿势是应该是:请使用在你的自动配置里(一般是你自定义starter时使用),而不是使用在你业务工程中的@Configuration里,因为那会毫无效果。

  为了更好的辅助理解,加强记忆,本文将这三大注解解析时机简要的絮叨一下,知道了它被解析的时机,自然就很好解释为何你那么写是无效的喽。

  这个排序的“解析/排序”过程还是比较复杂的,本文点到为止,观其大意即可。你可以简单粗暴的记住结论:@AutoConfigureBefore、@AutoConfigureAfter、@AutoConfigureOrder这三个注解只能作用于自动配置类,而不能是自定义的@Configuration配置类。

  关于Spring Boot自动配置顺序相关的三大注解@AutoConfigureBefore、@AutoConfigureAfter、@AutoConfigureOrder就先介绍到这了,本文主要用意是为了帮助大家规范此些“常用注解”的使用,规避一些误区,端正使用姿势,避免犯错时又丈二和尚。

  我看到不少文章、生产上的代码都使用错了(估计有没有效果自己的都不知道,又或者刚好歪打正着确实是在xxx后面执行而以为生效了),希望本文能帮助到你。

  打赏微信扫一扫,打赏作者吧~版权声明:所有来源为第三方内容,若本站收录的文章无意侵犯了贵司版权,请给下面邮箱地址来信,我们会及时处理和回复,谢谢。

  前言 最近在学习 Angular,一些基础的语法也学习的差不多了,就在 github 上新建了一个代码仓库,准备用 ng-zorro 搭个后台应用的模板,方便自己以后写些小东西时可以直接使用。前端项...

  作者:HelloGitHub——追梦人物 目前,用户对于接口的操作基本都需要查询数据库。获取文章列表需要从数据库查询,获取单篇文章需要从数据库查询,获取评论列表也需要查询数据。但是,对于博客中的...

  二哥,最近我刚进了一家公司,之前跟你说过,培训出身刚刚毕业,打算在北京打拼。最近进公司,给安排了工作,今天第一次没人带,自己上手搞代码,搞不出,明明挺简单的功能,自己还是做不出,不知道从哪里学习...

  首发先知社区: 前言 渐渐发现pam后门在实战中存在种植繁琐、隐蔽性不强等缺点,这里记录下学习pam后门相关知识和pam后门的拓展改进。...

  本文地址:本文参考了这篇文章 三元运算符 (如果您已经了解什么是三元运...

  一、回顾Stream管道流操作 通过前面章节的学习,我们应该明白了Stream管道流的基本操作。我们来回顾一下: 源操作:可以将数组、集合类、行文本文件转换成管道流Stream进行数据处理...