聊聊SpringBoot中的@EnableAutoConfiguration注解

本文详细探讨了SpringBoot中的@EnableAutoConfiguration注解的工作原理,从核心方法AutoConfigurationImportSelector入手,分析了getAutoConfigurationMetadata()和getAutoConfigurationEntry()等关键步骤,揭示了自动配置的加载、排序和过滤逻辑。同时,文章提到了自定义配置如何覆盖自动装配的条件,并对整个处理流程进行了总结。

引言

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

今天,我们就聊聊@EnableAutoConfiguration的处理逻辑。

找核心方法

@Enable开头的的注解上一般都有@Import用于指定要注解的逻辑实现类。

@EnableAutoConfiguration上的@Import,导入的是 AutoConfigurationImportSelector。

AutoConfigurationImportSelector就是要找的入口类。 类关系如下:

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered 

Aware系列都是用于注入响应的资源,Ordered用于排序。

值得关注的是 DeferredImportSelector,查看其类注释,简要翻译如下:

importselector的变体,在所有@Configuration bean之后运行,可以实现Ordered进行排序。

提供{getImportGroup(),它可以跨不同的选择器提供额外的排序和过滤逻辑。

DeferredImportSelector保证在所有@Configuration加载之后执行,也就是说,如果有相关配置类已加载,则可以跳过自动装配类。

DeferredImportSelector是如何保证在@Configuration bean加载之后执行的呢???

带着这个疑问,我查看了ConfigurationClassPostProcessor#processConfigBeanDefinitions

概要逻辑如下:

1. ImportSelector的解析在ConfigurationClassParser#processImports中处理在其中this.deferredImportSelectorHandler.handle(..)将DeferredImportSelector放入队列,延后处理。

2. DeferredImportSelector处理逻辑在ConfigurationClassParser#parse中的this.deferredImportSelectorHandler.process()中。

浏览this.deferredImportSelectorHandler.process()代码

DeferredImportSelectorGrouping#getImports的代码如下:

private static class DeferredImportSelectorGrouping {
        private final Group group;
        private final List<ConfigurationClassParser.DeferredImportSelectorHolder> deferredImports = new ArrayList();

        DeferredImportSelectorGrouping(Group group) {
            this.group = group;
        }

        public void add(ConfigurationClassParser.DeferredImportSelectorHolder deferredImport) {
            this.deferredImports.add(deferredImport);
        }

        public Iterable<Entry> getImports() {
            Iterator var1 = this.deferredImports.iterator();

            while(var1.hasNext()) {
                ConfigurationClassParser.DeferredImportSelectorHolder deferredImport = (ConfigurationClassParser.DeferredImportSelectorHolder)var1.next();
                this.group.process(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getImportSelector());
            }

            return this.group.selectImports();
        }

这里需要关注的是this.group.process,this.group.selectImports2个方法。

也就是AutoConfigurationImportSelector.AutoConfigurationGroup的process,selectImports就是我们需要关注的核心方法。

逐个分析

process

private static class AutoConfigurationGroup implements Group, BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware {
        private final Map<String, AnnotationMetadata> entries = new LinkedHashMap();
        private final List<AutoConfigurationImportSelector.AutoConfigurationEntry> autoConfigurationEntries = new ArrayList();
        private ClassLoader beanClassLoader;
        private BeanFactory beanFactory;
        private ResourceLoader resourceLoader;
        private AutoConfigurationMetadata autoConfigurationMetadata;

        private AutoConfigurationGroup() {
        }

        public void setBeanClassLoader(ClassLoader classLoader) {
            this.beanClassLoader = classLoader;
        }

        public void setBeanFactory(BeanFactory beanFactory) {
            this.beanFactory = beanFactory;
        }

        public void setResourceLoader(ResourceLoader resourceLoader) {
            this.resourceLoader = resourceLoader;
        }

        public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
            Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, () -> {
                return String.format("Only %
在 Spring Boot 中,`@EnableAutoConfiguration` 注解的核心作用是启用自动配置功能。它通过读取特定的配置文件来确定哪些自动配置类需要被加载。 ### 1. `@EnableAutoConfiguration` 注解读取的配置文件 `@EnableAutoConfiguration` 主要依赖于 `META-INF/spring.factories` 文件来获取自动配置类列表。该文件通常位于项目中的 `resources/META-INF/` 目录下,并包含以下格式的内容: ``` org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.MyAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration ``` Spring Boot 使用 `SpringFactoriesLoader` 来读取这个文件并加载其中定义的类名。这些类通常是与具体功能相关的自动配置类,例如数据库连接、Web 功能等 [^4]。 此外,`spring.factories` 文件还可以用来定义其他类型的工厂类,但 `@EnableAutoConfiguration` 只会关注 `org.springframework.boot.autoconfigure.EnableAutoConfiguration` 这一类别 [^1]。 ### 2. 配置文件的作用 - **`META-INF/spring.factories`**:这是主要的配置文件,用于指定所有可能需要的自动配置类。 - **`application.properties` 或 `application.yml`**:虽然不是直接由 `@EnableAutoConfiguration` 读取,但这些文件可以影响自动配置的行为。例如,如果希望禁用某些自动配置类,可以在 `application.properties` 中添加如下内容: ```properties spring.autoconfigure.exclude=com.example.MyAutoConfiguration ``` ### 3. 自动配置类的加载机制 当使用 `@EnableAutoConfiguration` 后,Spring Boot 会调用 `AutoConfigurationImportSelector` 类的 `getCandidateConfigurations()` 方法,从 `META-INF/spring.factories` 文件中读取所有需要加载的自动配置类 [^4]。此方法内部使用了 `SpringFactoriesLoader.loadFactoryNames()` 来完成实际的读取操作。 ### 4. 示例代码 以下是一个典型的 Spring Boot 应用程序主类,其中包含了 `@EnableAutoConfiguration` 的使用方式: ```java import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.ComponentScan; @EnableAutoConfiguration @ComponentScan(basePackages = "com.example") public class MyApp { public static void main(String[] args) { SpringApplication.run(MyApp.class, args); } } ``` 在这个例子中,`@EnableAutoConfiguration` 告诉 Spring Boot 开启自动配置功能,而 `@ComponentScan` 则指定了扫描组件的基础包路径 [^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值