欧博app:使用@AutoConfigureBefore调整设置顺序竟没生效?

admin/2020-07-08/ 分类:科技/阅读:

一个人的价值体现在能够辅助多少人。自己编码好,价值能获得很好的体现。若你做出来的器械能够辅助别人开发,大大削减开发的时间,那就功德无量。关注民众号【BAT的乌托邦】开启专栏式学习,拒绝浅尝辄止。本文 https://www.yourbatman.cn 已收录,内里一并有Spring手艺栈、MyBatis、中间件等小而美的专栏供以学习哦。

目录
  • 前言
  • 正文
    • 设置类为何需要顺序?
      • Spring下控制设置执行顺序
      • Spring Boot下控制设置执行顺序
    • Spring Boot内置的控制设置顺序举例
    • 三大注解使用的误区(主要)
      • 错误使用示例
    • 三大注解使用的准确姿势
      • 使用细节注重事项
    • 三大注解剖析时机浅析
  • 总结

前言

列位小伙伴人人好,我是A哥。Spring Boot是Spring家族具有划时代意义的一款产物,它生长自Spring Framework却又高于它,这种高于主要显示在其最主要的三大特征,而相较于这三大特征中更为主要的即是Spring Boot的自动设置AutoConfiguration)。与其说是自动,倒不如说是“智能”,该框架看起来似乎“更伶俐”了。因此它也顺理成章的成为了构建微服务的基础设施,稳坐第一宝座。

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

瑕不掩瑜,Spring Boot前进的措施声势赫赫,学就完了

这不,我就在前几天收到一个“求助”,希望使用@AutoConfigureBefore控制设置的顺序,但并未能如愿。本文就针对这个场景case稍作睁开,讨论下使用@AutoConfigureBefore、@AutoConfigureAfter、@AutoConfigureOrder三大注解控制自动设置执行顺序的准确姿势

提醒:Spring Boot的自动设置是通过@EnableAutoConfiguration注解驱动的,默认是开启状态。你也可以通过spring.boot.enableautoconfiguration = false来关闭它,回退到Spring Framework时代。显然这不是本文需要讨论的内容~

正文

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

设置类为何需要顺序?

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

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

那么针对于设置的执行顺序,传统Spring和Spring Boot下各自是若何处置的,显示若何呢?

Spring下控制设置执行顺序

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

// 手动控制Config1 Config2的顺序 ApplicationContext context = new AnnotationConfigApplicationContext(Config1.class, Config2.class); 

固然,你可能就疑问了说:纵然在传统Spirng里,我也从没有自己使用过AnnotationConfigApplicationContext来显示加载设置啊,都是使用@Configuration界说好设置类后,点击Run一把唆的。没错,那是由于你是在web环境下使用Spring,IoC容器是借助web容器(如Tomcat等)来驱动的,Spring对此部门封装得异常好,以是做到了对使用者险些无感知。

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

  1. 手动。构建ApplicationContext 时由构建者手动传入,可手动控制顺序
  2. 自动。被@ComponentScan自动扫描进去,无法控制顺序

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

Spring Boot下控制设置执行顺序

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

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

Spring Boot内置的控制设置顺序举例

为利便人人明白,我列出一个Spring Boot它自己的使用作为示例学一学。以人人最为熟悉的WebMvc的自动设置场景为例:

@Configuration(proxyBeanMethods = false) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE 10) @AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class }) public class WebMvcAutoConfiguration { ... } @Configuration(proxyBeanMethods = false) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) @AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class) public class DispatcherServletAutoConfiguration { ... } @Configuration(proxyBeanMethods = false) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) public class ServletWebServerFactoryAutoConfiguration { ... } 

这几个设置是WebMVC的焦点设置,他们之间是有顺序关系的:

  • WebMvcAutoConfiguration被加载的条件是:DispatcherServletAutoConfiguration、TaskExecutionAutoConfiguration、ValidationAutoConfiguration这三个哥们都已经完成初始化
  • DispatcherServletAutoConfiguration被加载的条件是:ServletWebServerFactoryAutoConfiguration已经完成初始化
  • ServletWebServerFactoryAutoConfiguration被加载的条件是:@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)最高优先级,也就是说它无其它依赖,希望自己是最先被初始化的
    • 当碰着多个设置都是最高优先级的时刻,且相互之前没有关系的话,顺序也是不定的。但若相互之间存在依赖关系(如本利的DispatcherServletAutoConfigurationServletWebServerFactoryAutoConfiguration),那就根据相对顺序走

WebMvcAutoConfiguration加载,在它之后着实另有许多设置会实验执行,例如:

@AutoConfigureAfter(WebMvcAutoConfiguration.class) class FreeMarkerServletWebConfiguration extends AbstractFreeMarkerConfiguration { ... } @AutoConfigureAfter(WebMvcAutoConfiguration.class) public class GroovyTemplateAutoConfiguration { ... } @AutoConfigureAfter({ WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class }) public class ThymeleafAutoConfiguration { ... } @AutoConfigureAfter(WebMvcAutoConfiguration.class) public class LifecycleMvcEndpointAutoConfiguration { ... } 

这些都很容易明白:若是都不是Web环境,加载一些模版引擎的并无需要嘛。

三大注解使用的误区(主要)

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

错误使用示例

我见到的异常多的小伙伴这么来使用三大注解:我这里使用“伪代码”举行模拟

@Configuration public class B_ParentConfig { B_ParentConfig() { System.out.println("设置类ParentConfig组织器被执行..."); } } @Configuration public class A_SonConfig { A_SonConfig() { System.out.println("设置类SonConfig组织器被执行..."); } } @Configuration public class C_DemoConfig { public C_DemoConfig(){ System.out.println("我是被自动扫描的设置,初始化啦...."); } } @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args).close(); } } 

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

启动应用,控制台打印:

设置类SonConfig组织器被执行... 设置类ParentConfig组织器被执行... 我是被自动扫描的设置,初始化啦.... 

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

@AutoConfigureBefore(A_SonConfig.class) @Configuration public class B_ParentConfig { B_ParentConfig() { System.out.println("设置类ParentConfig组织器被执行..."); } } 

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

设置类SonConfig组织器被执行... 设置类ParentConfig组织器被执行... 我是被自动扫描的设置,初始化啦.... 

what a fuck。看到没,我没骗你吧,骂街了骂街了


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

三大注解使用的准确姿势

针对以上case,要想到达预期效果,准确姿势只需要下面两步:

  1. A_SonConfigB_ParentConfig挪动到Application扫描不到的包内,切记:一定且必须是扫描不到的包内
  2. 当前工程里增添设置META-INF/spring.factories,内容为(设置里Son和Parent前后顺序对效果无影响):
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.fsx.autoconfig.A_SonConfig,com.fsx.autoconfig.B_ParentConfig 

再次启动应用看看,打印输出:

我是被自动扫描的设置,初始化啦.... 设置类ParentConfig组织器被执行... 设置类SonConfig组织器被执行... 

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

使用细节注重事项

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

  • 若你不用@AutoConfigureBefore这个注解,单单就想依赖于spring.factories里的先后顺序的来控制现实的加载顺序,谜底是不可以,控制不了
  • 例子中有个小细节:我每次都有意输出了我是被自动扫描的设置,初始化啦....这句话,可以发现被扫描进去设置实例化是在它前面(见错误示例),而通过spring.factories方式进去是在它的后面(见准确姿势)
  • 从这个小细节可以衍生获得结论:Spring Boot的自动设置均是通过spring.factories来指定的,它的优先级最低(执行时机是最晚的);通过扫描进来的一样平常都是你自己自界说的设置类,以是优先级是最高的,肯定在自动设置之前加载
    • 从这你应该学到:若你要指定扫描的包名,请万万不要扫描到形如org.springframework这种包名,否则“天下大乱”(固然喽为了防止这种情形泛起,Spring Boot做了容错的。它有一个类专门检测这个case防止你设置错了,详细参见ComponentScanPackageCheck默认实现)
  • 请只管不要让自动设置类既被扫描到了,又放在spring.factories设置了,否则后者会笼罩前者,很容易造成莫名其妙的错误

小总结,对于三大注解的准确使用姿势是应该是:请使用在你的自动设置里(一样平常是你自界说starter时使用),而不是使用在你营业工程中的@Configuration里,由于那会毫无效果。

三大注解剖析时机浅析

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

这三个注解的剖析都是交给AutoConfigurationSorter来排序、处置的,做法类似于AnnotationAwareOrderComparator去剖析排序@Order注解。焦点代码如下:

class AutoConfigurationSorter { // 唯一给外部挪用的方式:返回排序好的Names,因此返回的是个List嘛(ArrayList) List<String> getInPriorityOrder(Collection<String> classNames) { ... // 先根据自然顺序排一波 Collections.sort(orderedClassNames); // 在根据@AutoConfigureBefore这三个注解排一波 orderedClassNames = sortByAnnotation(classes, orderedClassNames); return orderedClassNames; } ... } 

此排序器被两个地方使用到:

  • AutoConfigurationImportSelector:Spring自动设置处置器,用于加载所有的自动设置类。它实现了DeferredImportSelector接口:这也顺便注释了为何自动设置是最后执行的缘故原由~
  • AutoConfigurations:示意自动设置@Configuration类。

这个排序的“剖析/排序”历程照样比较复杂的,本文点到为止,观其大意即可。你可以简朴粗暴的记着结论:@AutoConfigureBefore、@AutoConfigureAfter、@AutoConfigureOrder这三个注解只能作用于自动设置类,而不能是自界说的@Configuration设置类。

总结

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

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

,

px111.net

欢迎进入平心在线官网(原诚信在线、阳光在线)。平心在线官网www.px111.net开放平心在线会员登录网址、平心在线代理后台网址、平心在线APP下载、平心在线电脑客户端下载、平心在线企业邮局等业务。

TAG:
阅读:
广告 330*360
广告 330*360
Sunbet_进入申博sunbet官网
微信二维码扫一扫
关注微信公众号
新闻自媒体 Copyright © 2002-2019 Sunbet 版权所有
二维码
意见反馈 二维码