springboot源码解读-自动装配原理

340 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情

什么是自动装配

在使用SpringBoot的时候,会自动将Bean装配到IoC容器中,自动装配大致过程如下:

  • 获取到组件META-INF文件夹下的spring.factories文件
  • spring.factories文件中列出需要注入IoC容器的类
  • 将实体类注入到IoC容器中进行使用

自动装配原理

通过SpringBoot启动类 来分析整个过程,首先看下启动类的代码:

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

@SpringBootApplication

可以看到最主要部分就是@SpringBootApplication注解,进入注解类,我们能够发现@SpringBootApplication这个注解其实是一个组合注解

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

@Target({ElementType.TYPE}) // 表明 修饰的注解的位置 TYPE 表示只能修饰类

@Retention(RetentionPolicy.RUNTIME) // 表明注解的作用域

@Documented // API 文档抽取的时候会将该注解 抽取到API文档中

@Inherited // 表示注解的继承

@SpringBootConfiguration这个注解的本质其实是@Configuration注解。

@ComponentScan注解,该注解的作用是用来指定扫描路径的,如果不指定特定的扫描路径的话,扫描的路径是当前修饰的类所在的包及其子包。

那么就剩@EnableAutoConfiguration,这个注解就是SpringBoot自动装配的关键。

@EnableAutoConfiguration

进入@EnableAutoConfiguration注解,可以看到@AutoConfigurationPackage和@Import({AutoConfigurationImportSelector.class})

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

通过@AutoConfigurationPackage注解将添加该注解的类所在的package作为自动配置package进行管理。

而@EnableAutoConfiguration注解最重要的是AutoConfigurationImportSelector.class,将需要装配的类装配到IoC容器中,下面重点分析一下这个类的实现

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

进入到AutoConfigurationImportSelector 类,根据断点debug,进入getAutoConfigurationEntry方法,调用到了方法getCandidateConfigurations,调用到了 SpringFactoriesLoader的loadFactoryNames,通过debug可以看到加载到了META-INF/spring.factories文件

image.png

configurations = this.filter(configurations, autoConfigurationMetadata);调用下面方法
​
    private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
        long startTime = System.nanoTime();
        String[] candidates = StringUtils.toStringArray(configurations);
        boolean[] skip = new boolean[candidates.length];
        boolean skipped = false;
        Iterator var8 = this.getAutoConfigurationImportFilters().iterator();
​
        while(var8.hasNext()) {
            AutoConfigurationImportFilter filter = (AutoConfigurationImportFilter)var8.next();
            this.invokeAwareMethods(filter);
            boolean[] match = filter.match(candidates, autoConfigurationMetadata);
​
            for(int i = 0; i < match.length; ++i) {
                if (!match[i]) {
                    skip[i] = true;
                    candidates[i] = null;
                    skipped = true;
                }
            }
        }
​
        if (!skipped) {
            return configurations;
        } else {
            List<String> result = new ArrayList(candidates.length);
​
            int numberFiltered;
            for(numberFiltered = 0; numberFiltered < candidates.length; ++numberFiltered) {
                if (!skip[numberFiltered]) {
                    result.add(candidates[numberFiltered]);
                }
            }
​
            if (logger.isTraceEnabled()) {
                numberFiltered = configurations.size() - result.size();
                logger.trace("Filtered " + numberFiltered + " auto configuration class in " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
            }
​
            return new ArrayList(result);
        }
    }
​

可以看到匹配方法 match。 autoConfigurationMetadata,的本质是 加载的 META-INF/spring-autoconfigure-metadata.properties 的文件中的内容。过滤之后仅剩46个文件

image.png

总结

到这其实我们就已经给大家介绍完了SpringBoot的自动装配原理。在网上找到了一张总结好的流程图如下:

img

好了,本文就给大家介绍到这里,感觉有帮助的,留下个赞或评论再走吧!谢啦~ 💐