问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

SpringBoot 自动装配原理详解

创作时间:
作者:
@小白创作中心

SpringBoot 自动装配原理详解

引用
1
来源
1.
https://javaguide.cn/system-design/framework/spring/spring-boot-auto-assembly-principles.html

SpringBoot的自动装配机制是其核心特性之一,它极大地简化了Spring应用的配置过程。本文将深入探讨自动装配的原理,包括其工作流程、关键注解的作用,以及如何创建自定义的Starter。通过本文的学习,你将能够更好地理解和应用SpringBoot的自动装配功能。

前言

使用过Spring的开发者,一定对XML配置文件印象深刻。即使Spring引入了基于注解的配置方式,但在开启某些Spring特性或引入第三方依赖时,仍然需要进行显式配置。例如,在没有SpringBoot的情况下,创建一个RESTful Web服务需要如下配置:

@Configuration
public class RESTConfiguration {
    @Bean
    public View jsonTemplate() {
        MappingJackson2JsonView view = new MappingJackson2JsonView();
        view.setPrettyPrint(true);
        return view;
    }
    @Bean
    public ViewResolver viewResolver() {
        return new BeanNameViewResolver();
    }
}

而在Spring Boot项目中,我们只需要添加相关依赖,通过启动下面的main方法即可:

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

这种便捷性得益于Spring Boot的自动装配机制。那么,什么是自动装配?它是如何实现的?让我们一探究竟。

什么是SpringBoot自动装配?

自动装配的概念最早出现在Spring Framework中,而Spring Boot在其基础上进行了优化。Spring Boot定义了一套接口规范,规定在启动时扫描外部引用jar包中的META-INF/spring.factories文件(从Spring Boot 3.0开始,路径改为META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports),并将文件中配置的类型信息加载到Spring容器中。

在没有Spring Boot的情况下,引入第三方依赖需要手动配置,非常繁琐。而Spring Boot中,我们只需引入一个Starter即可。例如,要使用Redis,只需添加以下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

引入Starter后,通过少量注解和简单配置就能使用第三方组件的功能。自动装配可以理解为:通过注解或简单配置就能在Spring Boot帮助下实现某项功能。

SpringBoot是如何实现自动装配的?

我们先看Spring Boot的核心注解@SpringBootApplication

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
public @interface SpringBootApplication {
}

这个注解相当于@Configuration@EnableAutoConfiguration@ComponentScan的集合。其中,@EnableAutoConfiguration是实现自动装配的关键。

@EnableAutoConfiguration:实现自动装配的核心注解

@EnableAutoConfiguration通过AutoConfigurationImportSelector类实现自动装配的核心功能:

@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 {};
}

AutoConfigurationImportSelector:加载自动装配类

AutoConfigurationImportSelector类实现了ImportSelector接口,主要通过selectImports方法获取需要加载到IoC容器中的类:

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
    private static final String[] NO_IMPORTS = new String[0];
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }
}

重点关注getAutoConfigurationEntry方法:

private static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry();
AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
    if (!this.isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    } else {
        AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
        List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
        configurations = this.removeDuplicates(configurations);
        Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
        this.checkExcludedClasses(configurations, exclusions);
        configurations.removeAll(exclusions);
        configurations = this.filter(configurations, autoConfigurationMetadata);
        this.fireAutoConfigurationImportEvents(configurations, exclusions);
        return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
    }
}
  • 第1步:判断自动装配开关是否打开,默认spring.boot.enableautoconfiguration=true
  • 第2步:获取EnableAutoConfiguration注解中的excludeexcludeName
  • 第3步:读取META-INF/spring.factories文件,获取所有需要自动装配的配置类。
  • 第4步:通过@ConditionalOnXXX注解进行条件筛选,只有满足所有条件的类才会被加载。

如何实现一个Starter

创建一个自定义Starter的步骤如下:

  1. 创建threadpool-spring-boot-starter工程
  2. 引入Spring Boot相关依赖
  3. 创建ThreadPoolAutoConfiguration
  4. META-INF/spring.factories文件中配置自动装配类

总结

Spring Boot通过@EnableAutoConfiguration开启自动装配,通过SpringFactoriesLoader加载META-INF/spring.factories中的自动配置类。自动配置类通过@Conditional注解按需加载,只有满足所有条件的配置才会生效。要使自定义功能生效,需要创建一个Starter并引入相应的依赖。


© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号