SpringBoot 自动装配原理分析

29 篇文章 0 订阅

SpringBoot 自动装配原理分析

SpringBoot 中约定大于配置,这一原理使得配置文件量骤减,但也使得查找起来不太容易。只有了解了其背后的原理,知其然而知其所以然,才不会感到神奇和迷茫。

使用 SpringBoot 版本是: 2.2.6.RELEASE SpringBoot

先来看看 SpringBoot 的主配置类:

@Log4j2
@SpringBootApplication
public class DemoApplication {
	public static void main(String[] args) {
		SpringApplication app = new SpringApplication(MingshiApplication.class);
		app.addListeners(new ApplicationPidFileWriter());
		app.run(args);
	}
}	

@SpringBootApplication 注解,SpringBoot的这个注解应用在哪个类上就说明这个类是主配置类,SpringBoot就会运行这个类中 main 方法来启动 SpringBoot 项目。那么这个注解到底是什么呢,点进去看看:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
 

可以看到 @SpringBootApplication 是一个组合注解。先点击 @SpringBootConfiguration 这个配置类看看:

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

这个注解很简单,表明改类是一个配置类。点击 @Configuration 看看:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {

@Component 注解说明 Spring的配置类也是 Spring的一个组件,这个也是很简单的注解。

下面我们返回到 @SpringBootApplication 中的 @EnableAutoConfiguration注解,根据字面翻译猜测这个注解是关于自动配置相关的,点击进去看看:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {

先看看@AutoConfigurationPackage注解:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
}

这个注解是自动配置包,只要使用 @Import 来给 Spring 容器中导入一个组件,这里导入的 Registrar.class。

点击查看 Registrar.class :

    static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
        Registrar() {
        }

        public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
        }

        public Set<Object> determineImports(AnnotationMetadata metadata) {
            return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));
        }
    }

registerBeanDefinitions() 方法,就是通过这个方法获取扫描的包路径,可以debug看看,在这行代码上打了一个断点:
在这里插入图片描述

点击 Evaluate Expresson ,弹出的窗口中点击 Evaluate 按钮,显示获取到的包路径:

在这里插入图片描述

那那个metadata是什么呢,在debugger分析器中查看,可以看到是标注在@SpringBootApplication注解上的DemosbApplication,也就是我们的主配置类
在这里插入图片描述

说白了就是将主配置类(即@SpringBootApplication标注的类)的所在包及子包里面所有组件扫描加载到Spring容器。所以包名一定要注意。

现在包扫描路径获取到了,那具体加载哪些组件呢,看看下面这个注解。
在这里插入图片描述
@Import导入的是AutoConfigurationImportSelector 类,(@Import组件就是给Spring容器导入一些组件),点击AutoConfigurationImportSelector 类,看到里面有个方法 getAutoConfigurationEntry(),将所有需要导入的组件以全类名的方式返回;这些组件就会被添加到容器中。

    protected AutoConfigurationImportSelector.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);
        }
    }

debug进来查看导入的配置文件:
在这里插入图片描述

会给容器中导入非常多的自动配置类(xxxAutoConfiguration);就是给容器中导入这个场景需要的所有组件,并配置好这些组件,有了自动配置类,免去了我们手动编写配置注入功能组件等的工作。

那他是如何获取到这些配置类的呢,看看上面这个方法:

... ...
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
... ...

//方法实现
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
        Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
        return configurations;
    }

Spring Boot在启动的时候从类路径下的 META-INF/spring.factories 中获取 EnableAutoConfiguration 指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作。以前我们需要自己配置的东西,自动配置类都帮我们完成了。

现在来查看 Spring Boot 中默认的配置文件给我们配置了什么,spring-boot-autoconfigure-2.1.8.RELEASE.jar:
在这里插入图片描述
打开 META-INF/spring.factories 文件,可以看到很多的内容。如果在自己的工程中要加扩展的自动配置内容,就要在自己的工程目录结构 META-INF/spring.factories 文件中,按照系统的这个文件例子来配置。

总结:注解 @SpringBootApplication 和 @EnableAutoConfiguration;路径 META-INF/spring.factories,Spring Boot 主方法启动后按照路径进行扫描,所有要注意包的路径。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值