当前位置:   article > 正文

SpringBoot笔记------自动配置_springboot自动配置

springboot自动配置

SpringBoot-自动配置

在Springboot中,有各种各样的starter(启动器),比如spring-boot-starter-web等,Maven引入Starter后,只需要启动,无需手动配置,容器便可以自动配置必要的默认配置(其实是已经约定写好的配置),查看各个Starter的依赖,无一例外都会依赖“spring-boot-starter”,以2.3.4版本为例,这里上部分Maven代码:

 	<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <version>2.3.4.RELEASE</version>
      <scope>compile</scope>
    </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

进入spring-boot-starter依赖:

 	<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot</artifactId>
      <version>2.3.4.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-autoconfigure</artifactId>
      <version>2.3.4.RELEASE</version>
      <scope>compile</scope>
    </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

可以看到,每一个启动器,最终都需要依赖spring-boot-autoconfigure进行自动配置,这个包下主要还是一堆自动配置类AutoConfiguration,其中还有一个核心配置文件:spring.factories,以及相关注解@SpringBootApplication等等

核心注解:@EnableAutoConfiguration

每个javaer学习springboot时,无一例外都是从使用@SpringBootApplication注解在自己写的XXXApplication启动类上,再在类里面实现一个main方法,方法里用SpringApplication.run()启动springboot应用开始,而EnableAutoConfiguration便是其中核心;

通过源码进行分析

@SpringBootApplication源码:

package org.springframework.boot.autoconfigure;
@SpringBootConfiguration
@EnableAutoConfiguration //核心在于此,进入
@ComponentScan(....)
public @interface SpringBootApplication {
//省略..........
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

@EnableAutoConfiguration源码:

@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class}) //核心在于此,进入
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";//是否开启自动配置,可以在application.yml或properties中配置
...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

(注意前置知识:Spring将组件注册进容器有哪些方式)

AutoConfigurationImportSelector源码:

	public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }
    
    protected 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 AutoConfigurationEntry(configurations, exclusions);
        }
    }
    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;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

在方法selectImports中,返回的数组里面的类名均会被注册进容器中,依次调用了getAutoConfigurationEntry->getCandidateConfigurations,而getCandidateConfigurations便是最核心的方法,通过SpringFactoriesLoader把自动配置类加载进容器中;
加载过程见SpringFactoriesLoader源码:

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        ClassLoader classLoaderToUse = classLoader;
        if (classLoader == null) {
            classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
        }

        String factoryTypeName = factoryType.getName();
        return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
    }

    private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
        Map<String, List<String>> result = (Map)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            Map<String, List<String>> result = new HashMap();

            try {
                Enumeration<URL> 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()) {
                        Map.Entry<?, ?> entry = (Map.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());
                        }
                    }
                }

                result.replaceAll((factoryType, implementations) -> {
                    return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
                });
                cache.put(classLoader, result);
                return result;
            } catch (IOException var14) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

spring.factories(本质是一个properties键值对文件):
在这里插入图片描述

此时,SpringFactoriesLoader.loadFactoryNames方法的第一个参数为EnableConfiguration.class,在方法内,通过类加载器加载classpath下的资源"META-INF/spring.factories",把spring.factories中EnableAutoConfiguration作为Key,对应的xxxAutoConfiguration的类名列表作为value,读进MapMap<String, List>中,经过过滤在AutoConfigurationImportSelector. selectImports返回注入的数组,于是自动配置类便被注入到容器中;
所以,当自己写的jar包想要被扫描到容器中,也可以自己写一个spring.factories,Key选用org.springframework.boot.autoconfigure.EnableAutoConfiguration,也会将Value自动注入到容器中:
在这里插入图片描述
再来看看org.springframework.boot.autoconfigure下的xxxxxAutoConfiguration
在这里插入图片描述
这些配置类也不是说加载就加载的,只有@ConditionalOnXXX生效了,符合特定条件,才能被注入到容器中并生效;

总结

Springboot自动配置概括为,核心在启动注解@SpringBootApplication的@EnableAutoConfiguration注解,通过@Import注解引入AutoConfigurationImportSelector类,经过一系列调用,最后调用SpringFactoriesLoader类加载spring.factories文件,并把文件中key为EnableAutoConfiguration的value全部加载进容器中,再根据当前依赖环境过滤后,最后才能被注入进容器,从而完成自动配置。

SpringBoot 2.7.0 以后的自动配置:

在最新的springboot中,仍旧支持spring.factories,但后续将被慢慢废弃;
主要优化有:
1.spring.factories中,org.springframework.boot.autoconfigure.EnableAutoConfiguration=\的key全部迁移至 META-INF\spring\org.springframework.boot.autoconfigure.AutoConfiguration.imports
2.新增注解类AutoConfiguration,并修改了AutoConfigurationImportSelector.getCandidateConfigurations方法,如下,也就是将自动配置类放在imports文件里,并加到候选配置列表中;
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/346937
推荐阅读
相关标签
  

闽ICP备14008679号