SpringBoot: @AutoConfigureAfter 和 @AutoConfigureBefore失效问题

目录

问题场景

几个注解

问题分析

Spring加载配置文件

SpringBoot加载配置文件

错误示例

正确示例


问题场景

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

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

几个注解

  • @ComponentScan

        自动扫描组件。value 指定扫描的包路径,将包路径下标识了需要装配的类(@Controller,@Service,@Repository,@Configuration等)自动装配到Spring的bean容器中。

        启动SpringBoot时,如果配置了@ComponentScan,则扫描包路径为配置的包路径;如果没配置@ComponentScan,扫描包路径默认为SpringBootApplication启动类所在的包路径。

  • @Configuration

        修饰类,表明当前类是一个配置类,如果该类在@ComponentScan指定的包路径下,那么在启动SpringBoot时,就会自动将该类装配到Spring的Bean容器中。

  • @AutoConfigurationAfter

        表明当前配置类在某一个配置类加载后加载。

  • @AutoConfigurationBefore

        表明当前配置类在某一个配置类加载前加载。

问题分析

  • 自动配置类

        我们平时引入pom依赖时,这些依赖包的配置会自动注入到Spring容器中。最常见的是会自动加载META-INF下的spring.factories文件中定义的配置类。

  • 自定义配置类

        可以简单理解为使用@Configuration注解的类。

@AutoConfigureAfter 和 @AutoConfigureBefore 在自动配置类上才会生效,自定义的配置类是不会生效的。

Spring加载配置文件

  • 方式一:构建ApplicationContext时手动传入配置文件类,可控制配置文件加载顺序。
ApplicationContext context = new AnnotationConfigApplicationContext(Config1.class, Config2.class);
  • 方式二:使用@Configuration和@ComponentScan自动扫描配置类,无法控制加载顺序。

SpringBoot加载配置文件

        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就会失效。

错误示例

  • 启动类指定扫描路径为com.example.config
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");
    }
}
  • 结果

 从结果看出,@AutoConfigureBefore和@AutoConfigureAfter生效了。

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

以上内容为个人学习理解,如有问题,欢迎在评论区指出。

  • 6
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值