SpringBoot自动配置原理

SpringBoot是实现自动配置主要有以下三个重要注解

1@SpringBootApplication

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

我们可以点击进去@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 {
  • @SpringBootConfiguration:我们点进去以后可以发现底层是Configuration注解,说白了就是支持JavaConfig的方式来进行配置(使用Configuration配置类等同于XML文件)。
  • @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Configuration
    @Indexed
    public @interface SpringBootConfiguration {
        @AliasFor(
            annotation = Configuration.class
        )
        boolean proxyBeanMethods() default true;
    }

  • @EnableAutoConfiguration:开启自动配置功能
  • @ComponentScan:这个注解,学过Spring的同学应该对它不会陌生,就是扫描注解,默认是扫描当前类下的package。将@Controller/@Service/@Component/@Repository等注解加载到IOC容器中。

2重点EnableAutoConfiguration

我们点进去看一下,发现有两个比较重要的注解:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
  • @AutoConfigurationPackage:自动配置包
  • @Import:给IOC容器导入组件
  • @Import注解

    @Enable底层依赖于@Import注解导入一些类,使用@Import导入的类会被Spring加载到IOC容器中。而@Import提供4中用法:

    ① 导入Bean

    ② 导入配置类

    ③ 导入 ImportSelector 实现类。一般用于加载配置文件中的类

    ④ 导入 ImportBeanDefinitionRegistrar 实现类。

    @AutoConfigurationPackage :自动配置包
  • 再回到@Import(AutoConfigurationImportSelector.class)这句代码上,再点进去AutoConfigurationImportSelector.class看看具体的实现是什么
  • protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(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.getConfigurationClassFilter().filter(configurations);
                this.fireAutoConfigurationImportEvents(configurations, exclusions);
                return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
            }
        }

    我们再进去看一下这些配置信息是从哪里来的(进去getCandidateConfigurations方法):

  •  protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
            List<String> configurations = new ArrayList(SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()));
            ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).forEach(configurations::add);
            Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.");
            return configurations;
        }

    再点进去

  •  private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
            Map<String, List<String>> result = (Map)cache.get(classLoader);
            if (result != null) {
                return result;
            } else {
                HashMap result = new HashMap();
    
                try {
                    Enumeration urls = classLoader.getResources("META-INF/spring.factories");
                      //加载的是这里
                    while(urls.hasMoreElements()) {
                        URL url = (URL)urls.nextElement();
                        UrlResource resource = new UrlResource(url);
                        Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                        Iterator var6 = properties.entrySet().iterator();
    
                        while(var6.hasNext()) {
                            Entry<?, ?> entry = (Entry)var6.next();
                            String factoryTypeName = ((String)entry.getKey()).trim();
                            String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                            String[] var10 = factoryImplementationNames;
                            int var11 = factoryImplementationNames.length;
    
                            for(int var12 = 0; var12 < var11; ++var12) {
                                String factoryImplementationName = var10[var12];
                                ((List)result.computeIfAbsent(factoryTypeName, (key) -> {
                                    return new ArrayList();
                                })).add(factoryImplementationName.trim());
                            }
                        }
                    }

  • SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值
  • 将这些值作为自动配置类导入容器 , 自动配置类就生效 , 帮我们进行自动配置工作
  • 从Properties对象获取到key值为EnableAutoConfiguration的数据,然后添加到容器里边。
  • 它会给容器中导入非常多的自动配置类 (XxxAutoConfiguration), 就是给容器中导入这个场景需要的所有组件 , 并配置好这些组件
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值