AutoConfigureBefore不生效

简介: AutoConfigureBefore不生效

问题:

项目启动时需要加载多个配置类,且需要控制某些配置类的加载顺序。使用@Configuration标注配置类,使用@AutoConfigureAfter、@AutoConfigureBefore设置配置类加载顺序

结果:能够正常加载配置类,但无法控制配置类的加载顺序。

Spring加载配置文件

方式一:构建ApplicationContext时手动传入配置文件类,可控制配置文件加载顺序。

ApplicationContext context = new AnnotationConfigApplicationContext(Config1.class, Config2.class);

方式二:使用@Configuration和@ComponentScan自动扫描配置类,无法控制加载顺序。

SpringBoot下可以通过@Configuration自动扫描配置类和spring.factories来加载配置类,但这两种方式都无法控制加载顺序。

此时,可通过在配置类上增加@AutoConfigureAfter 、 @AutoConfigureBefore和@AutoConfigureOrder来控制配置文件加载的相对顺序。

前两个注解在SpringBoot1.0.0就支持了,而@AutoConfigureOrder注解则是在SpringBoot1.3.0版本新增。

SpringBoot的自动配置是通过spring.factories来指定的,它的优先级最低,加载时间最晚,spring.factories中的配置类顺序不代表实际加载顺序。可结合 @AutoConfigureAfter 和 @AutoConfigureBefore注解控制配置类的相对加载顺序。

通过@Configuration和@ComponentScan扫描加载的配置类,一般是我们自定义的配置类,这部分配置类优先级最高,加载时间最早,在加载spring.factories配置类前加载,但加载顺序不定。

注意:@AutoConfigureAfter 和 @AutoConfigureBefore 只有在自动配置类上才会生效。如果一个配置类是通过@Configuration扫描加载,那么@AutoConfigureAfter 和 @AutoConfigureBefore就会失效。

错误示例

package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan("com.example.config")
public class BootStrapApplication {
    public static void main(String[] args) {
        SpringApplication.run(BootStrapApplication.class);
    }
}
两个config类,在Config2上增加@AutoConfigureBefore(Config1.class),希望配置按config2、config1加载
package com.example.config;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Config1 {
    Config1() {
        System.out.println("this is Config1");
    }
}
package com.example.config;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.context.annotation.Configuration;
@Configuration
@AutoConfigureBefore(Config1.class)
public class Config2 {
    Config2() {
        System.out.println("this is Config2");
    }
}

正确示例

在错误示例的基础上,增加以下配置:

定义spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.example.autoconfig.AutoConfig1,\
  com.example.autoconfig.AutoConfig2,\
  com.example.autoconfig.AutoConfig3

定义自动配置类,使用@AutoConfigureBefore和@AutoConfigureAfter注解,期望按AutoConfig3、AutoConfig2、AutoConfig1顺序加载。

package com.example.autoconfig;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
@AutoConfigureAfter(AutoConfig2.class)
public class AutoConfig1 {
    AutoConfig1() {
        System.out.println("this is AutoConfig1");
    }
}
package com.example.autoconfig;
public class AutoConfig2 {
    AutoConfig2() {
        System.out.println("this is AutoConfig2");
    }
}
package com.example.autoconfig;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
@AutoConfigureBefore(AutoConfig2.class)
public class AutoConfig3 {
    AutoConfig3() {
        System.out.println("this is AutoConfig3");
    }
}

启动顺序:3 --> 2 --> 1 @AutoConfigureBefore和@AutoConfigureAfter生效了。

且Config先于AutoConfig加载,说明通过扫描加载的自定义配置类优先级更高,加载时间最早;通过spring.factories加载的配置类优先级更低,加载时间最晚。


再看一个例子

预期加载顺序:C --> B --> A

@Configuration
@AutoConfigureAfter(ConfigurationB.class)
public class ConfigurationA {
    ConfigurationA(){
        System.out.println("CofigurationA  已经被初始化!");
    }
}
@Configuration
@AutoConfigureAfter(ConfigurationC.class)
public class ConfigurationB {
    ConfigurationB(){
        System.out.println("ConfigurationB  已经被初始化!");
    }
}
@Configuration
public class ConfigurationC {
    ConfigurationC(){
        System.out.println("CofigurationC  已经被初始化!");
    }
}

结果:

CofigurationA   已经被初始化!
ConfigurationB  已经被初始化!
CofigurationC   已经被初始化!

如上使用@AutoConfigureBefore@AutoConfigureAfter@AutoConfigureOrder调整配置顺序,不会生效,结果打印顺序依然是a、b、c

如果想通过@AutoConfigureAfter@AutoConfigureBefore@AutoConfigureOrder保证bean的加载顺序可通过一下方式:

  • 将配置类放在Spring扫描路径里外面(scanBasePackages)
  • 如果还是想放在扫描路径里面就需要将@Configuration注解去掉
  • 指定顺序:添加文件META-INF/spring.factories
    在spring.factories中配置
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.*******.Demo.ConfigurationA,\
com.*******.Demo.ConfigurationB,\
com.*******.Demo.ConfigurationC


相关文章
|
SQL XML 安全
mybatis批量更新数据三种方法效率对比【Mysql】
mybatis批量更新数据三种方法效率对比【Mysql】
3151 0
mybatis批量更新数据三种方法效率对比【Mysql】
|
消息中间件 Java 物联网
一文搞懂MQTT,如何在SpringBoot中使用MQTT实现消息的订阅和发布
之前介绍了RabbitMQ以及如何在SpringBoot项目中整合使用RabbitMQ,看过的朋友都说写的比较详细,希望再总结一下目前比较流行的MQTT。所以接下来,就来介绍什么MQTT?它在IoT中有着怎样的作用?如何在项目中使用MQTT?
13257 5
一文搞懂MQTT,如何在SpringBoot中使用MQTT实现消息的订阅和发布
|
6月前
|
Java Spring
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
`@RequiredArgsConstructor(onConstructor = @__(@Autowired))` 是一个注解,通常用于在类中生成一个包含所有`final`和`@NonNull`注解的字段的构造函数,并且对这些字段进行自动注入(使用Spring框架的`@Autowired`注解)。让我们详细解释一下: 1. **`@RequiredArgsConstructor` 注解:** - **作用:** Lombok 提供的注解,用于自动生成类的构造函数。 - **生成的构造函数:** 生成一个包含所有`final`字段的构造函数,同时也包括被`@NonNull`注解
642 1
|
Java Spring
RestTemplate上传文件解决方案
当对接文件上传模块时,需要对接上传文件的接口,而我们模块的数据是以字节数组存在的(已经操作过了的字节数组,存在于内存中)接口是以form-data的形式上传的,其中需要上传MultipartFIle,如果使用MultipartFile放入到请求的 fromMap中,然后再上传这个文件,会报(ByteArrayInputStream no serialized)的错误,也就是没有注入对应的bean的错误。。
4530 0
|
JSON 数据格式
JSON - JSON.toJSONString 格式化成 JSON 字符串时保留 null 属性
JSON - JSON.toJSONString 格式化成 JSON 字符串时保留 null 属性
1266 0
|
缓存 Java 程序员
Spring中异步注解@Async的使用、原理及使用时可能导致的问题
本文主要介绍了Spring中异步注解的使用、原理及可能碰到的问题,针对每个问题文中也给出了方案。希望通过这篇文章能帮助你彻底掌握`@Async`注解的使用,知其然并知其所以然!
13091 4
|
前端开发 Java Spring
SpringBoot2.6.x 整合swagger3.0 报错Failed to start bean ‘documentationPluginsBootstrapper‘
org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException
13916 3
SpringBoot2.6.x 整合swagger3.0 报错Failed to start bean ‘documentationPluginsBootstrapper‘
|
缓存
RestTemplate请求访问简单使用
RestTemplate请求访问简单使用
89 1
|
Java 数据库连接 网络安全
已解决 IDEA Maven 项目中 “Could not find artifact“ 问题的常见情况和解决方案
已解决 IDEA Maven 项目中 “Could not find artifact“ 问题的常见情况和解决方案
10120 0
|
存储 关系型数据库 MySQL
PostgreSQL与MySQL优劣势比较浅谈
PostgreSQL与MySQL优劣势比较浅谈
820 0