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


相关文章
|
存储 JSON 网络协议
ElasticsearchRestTemplate客户端使用
ElasticsearchRestTemplate客户端使用
|
JavaScript Java Maven
|
前端开发 Java 开发者
【springboot】中使用--WebMvcConfigurer
通过实现 `WebMvcConfigurer` 接口,Spring Boot 开发者可以灵活地自定义和扩展 Spring MVC 的配置。无论是视图解析、拦截器、跨域请求处理,还是静态资源和消息转换器配置,`WebMvcConfigurer` 都提供了一致的接口来实现这些功能。掌握这些配置方法,可以使开发者在 Spring Boot 项目中更加游刃有余地进行各种定制化需求的开发。
708 14
|
Java
SpringBoot 内部方法调用,事务不起作用的原因及解决办法
在做业务开发时,遇到了一个事务不起作用的问题。大概流程是这样的,方法内部的定时任务调用了一个带事务的方法,失败后事务没有回滚。查阅资料后,问题得到解决,记录下来分享给大家。
771 4
|
移动开发 网络协议 算法
(十)Netty进阶篇:漫谈网络粘包、半包问题、解码器与长连接、心跳机制实战
在前面关于《Netty入门篇》的文章中,咱们已经初步对Netty这个著名的网络框架有了认知,本章的目的则是承接上文,再对Netty中的一些进阶知识进行阐述,毕竟前面的内容中,仅阐述了一些Netty的核心组件,想要真正掌握Netty框架,对于它我们应该具备更为全面的认知。
958 2
|
XML 搜索推荐 Java
Elasticsearch集成到Spring Boot项目
将Elasticsearch集成到Spring Boot项目中,可以方便地实现数据的搜索、分析等功能。
734 2
|
Java Spring
在Spring Boot中,可以通过控制`@PostConstruct`注解方法的执行顺序来实现初始化时的顺序控制
在Spring Boot中,可以通过控制`@PostConstruct`注解方法的执行顺序来实现初始化时的顺序控制
1356 1
|
Java 开发者 Spring
springboot @Primary的概念与使用
【4月更文挑战第26天】在 Spring Framework 中,@Primary 注解用于标记一个 bean 作为在多个同类型的 bean 候选中进行自动装配时的首选 bean。这个注解非常有用,在配置和自动装配复杂的 Spring 应用程序时尤其如此,特别是当有多个 bean 实现相同的接口或继承相同的类时
1415 3
|
监控 Java API
Spring Cloud 之 GateWay
Spring Cloud Gateway 作为API网关,处理客户端与微服务间的非业务逻辑,如权限验证、监控、路由转发。它通过Route(含ID、目标URI、Predicate和Filter)、Predicate(匹配请求条件)和Filter(请求前/后处理)实现动态路由。工作流程包括客户端请求->Gateway Handler Mapping->过滤器链->服务转发->响应过滤->回客户端。过滤器用于请求拦截、响应处理,如参数校验、权限检查。动态路由允许以服务名创建路由,实现服务发现。预设和全局过滤器用于特定或所有路由的定制逻辑,例如登录验证和请求头管理。

热门文章

最新文章