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

简介: 使用@AutoConfigureBefore调整配置顺序竟没生效?(上)

前言


各位小伙伴大家好,我是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)最高优先级,也就是说它无其它依赖,希望自己是最先被初始化的
  • 当碰到多个配置都是最高优先级的时候,且互相之前没有关系的话,顺序也是不定的。但若互相之间存在依赖关系(如本利的DispatcherServletAutoConfiguration和ServletWebServerFactoryAutoConfiguration),那就按照相对顺序走



image.png



相关文章
|
JSON 缓存 Java
Springboot 之 Filter 实现超大响应 JSON 数据压缩
Springboot 之 Filter 实现超大响应 JSON 数据压缩
354 0
|
存储 JSON Kubernetes
Kubernetes必备知识: Kubernetes Flexvolume
FlexVolume 是 Kubernetes v1.8+ 支持的一种存储插件扩展方式。类似于 CNI 插件,它需要外部插件将二进制文件放到预先配置的路径中(如 /usr/libexec/kubernetes/kubelet-plugins/volume/exec/),并需要在系统中安装好所有需要的依赖。可以想到,这是一种out-tree的扩展方式,不需要新增加一种存储插件,去更改k8s的源码。
1759 0
Kubernetes必备知识: Kubernetes Flexvolume
|
SQL 人工智能 运维
在阿里云日志服务轻松落地您的AI模型服务——让您的数据更容易产生洞见和实现价值
您有大量的数据,数据的存储和管理消耗您大量的成本,您知道这些数据隐藏着巨大的价值,但是您总觉得还没有把数据的价值变现出来,对吗?来吧,我们用一系列的案例帮您轻松落地AI模型服务,实现数据价值的变现......
495 3
|
8月前
|
存储 文件存储 对象存储
AI 场景下,函数计算 GPU 实例模型存储最佳实践
当前,函数计算 FC 已被广泛应用在各种 AI 场景下,函数计算支持通过使用容器镜像部署 AI 推理应用,并且提供多种选项来访问训练好的模型。为了帮助开发者高效地在函数计算上部署 AI 推理应用,并快速解决不同场景下的模型存储选型问题,本文将对函数计算的 GPU 模型存储的优缺点及适用场景进行对比分析,以期为您的模型存储决策提供帮助。
|
前端开发 Java 应用服务中间件
计算机Java项目|基于SpringBoot的在线视频教育平台的设计与实现
计算机Java项目|基于SpringBoot的在线视频教育平台的设计与实现
220 0
springboot自定义拦截器,校验token
springboot自定义拦截器,校验token
750 6
|
Kubernetes 应用服务中间件 Apache
理解Kubernetes中的Pod — 容器协同工作
当你在Kubernetes中部署一个应用程序时,你通常会使用Pod作为最小的可部署单元。Pod是一个可以包含一个或多个容器的组。这些容器在Pod内部共享网络和存储,并可以通过localhost直接通信。这种设计使得它们能够协同工作,共享数据,并能够一起被调度和管理。
331 1
|
网络协议 Linux
Linux 的端口区间
在 Linux 中,端口区间分配和使用如下: 1. 0到1023端口是系统保留的端口,由一些通用协议、应用程序及其服务使用。这些端口被标识为众所周知的端口,并且不能被用户程序使用。 2. 1024到49151端口是为用户程序保留的,通常也称为注册端口。这些端口须先在IANA(互联网号码分配局)注册,以避免端口冲突。在进行应用程序开发时,应尽可能分配一个注册端口。 3. 49152到65535端口是为临时使用而保留的。这个端口范围通常用于不需要长期占据端口的应用程序,例如下载和文件共享应用程序。 至于如何使用这些端口区间,这取决于应用程序的设计和功能。例如,FTP服务器的默认控制连接端口为1
979 0
|
存储 Web App开发 编解码
FastASR+FFmpeg(音视频开发+语音识别)(一)
FastASR+FFmpeg(音视频开发+语音识别)(一)
288 0
|
开发工具 git
git submodule update --init --recursive失败的处理办法
git submodule update --init --recursive失败的处理办法
3477 0