Spring-自动配置

自动配置流程细节梳理:
1、导入starter-web:导入了web开发场景

  • 1、场景启动器导入了相关场景的所有依赖:starter-jsonstarter-tomcatspringmvc
  • 2、每个场景启动器都引入了一个spring-boot-starter,核心场景启动器。(上面三个也有)
  • 3、核心场景启动器引入了spring-boot-autoconfigure包。
  • 4、spring-boot-autoconfigure里面囊括了所有场景的所有配置。
  • 5、只要这个包下的所有类都能生效,那么相当于SpringBoot官方写好的整合功能就生效了。
  • 6、SpringBoot默认却扫描不到 spring-boot-autoconfigure下写好的所有配置类。(这些配置类给我们做了整合操作),默认只扫描主程序所在的包。

2、主程序:@SpringBootApplication

  • 1、@SpringBootApplication由三个注解组成@SpringBootConfiguration声明配置类、@EnableAutoConfiguratio@ComponentScan扫描指定组件包
  • 2、SpringBoot默认只能扫描自己主程序所在的包及其下面的子包,扫描不到 spring-boot-autoconfigure包中官方写好的配置类
  • 3、@EnableAutoConfiguration:SpringBoot 开启自动配置的核心。
    • 1、是由@Import(AutoConfigurationImportSelector.class)提供功能:批量给容器中导入组件。
    • 2、SpringBoot启动会默认加载 142个配置类。
    • 3、这142个配置类来自于spring-boot-autoconfigureMETA-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件指定的
      项目启动的时候利用 @Import 批量导入组件机制把 autoconfigure 包下的142 xxxxAutoConfiguration类导入进来(自动配置类)命名规范都是以xxxxAutoConfiguration结尾的自动配置类
      虽然导入了142个自动配置类
    • 4、按需生效:
      并不是这142个自动配置类都能生效
      每一个自动配置类,都有条件注解@ConditionalOnxxx,只有条件成立,才能生效

3、xxxxAutoConfiguration自动配置类

  • 1、给容器中使用@Bean 放一堆组件
  • 2、每个自动配置类都可能有这个注解@EnableConfigurationProperties(ServerProperties.class),用来把配置文件中配的指定前缀的属性值封装到 xxxProperties属性类
  • 3、以Tomcat为例:把服务器的所有配置都是以server开头的。配置都封装到了属性类中
  • 4、给容器中放的所有组件的一些核心参数,都来自于xxxPropertiesxxxProperties都是和配置文件绑定。
  • 只需要改配置文件的值,核心组件的底层参数都能修改

核心流程总结:
1、导入starter,就会导入autoconfigure包。
2、autoconfigure 包里面 有一个文件 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports,里面指定的所有启动要加载的自动配置类
3、@EnableAutoConfiguration 会自动的把上面文件里面写的所有自动配置类都导入进来。xxxAutoConfiguration 是有条件注解进行按需加载
4、xxxAutoConfiguration给容器中导入一堆组件,组件都是从 xxxProperties中提取属性值
5、xxxProperties又是和配置文件进行了绑定
效果:导入starter、修改配置文件,就能修改底层行为。

点开依赖,找到autoconfigure


autoconfigure包里面写了SpringBoot官方的所有场景的全场景的各种配置
比如Web相关的所有配置

JDBC相关的所有配置


public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware
      ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered{

    //批量导入组件
    @0verride
    public String[] selectImports(AnnotationMetadata annotationMetadata){
        if(!isEnabled(annotationMetadata)){
          return NO_IMPORTS;
        }
        AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata)
        return stringUtils.toStringArray(autoConfiqurationEntry.getConfigurations());
}

SpringBoot加载进来24个配置,这些配置又是从哪来的

可以看到是从getCandidateConfigurations方法里返回的全类名。
getCandidateConfigurations方法看看

可以看到是调用了工具类ImportCandidates,然后loadAutoconfiguration.class这个类,configurations现在默认有140+个配置类,远大于返回的24个配置类。
如果找不到这个配置类,则会报错,沿着提示给的路径去看看文件

可以看到文件里存着140多个全类名,并且都以AutoConfiguration为结尾。

//以Tomcat为例
//属性绑定,追入ServerProperties.class看看
@AutoConfiguration
@ConditionalOnNotWarDeployment
@ConditionalOnWebApplication
@EnableConfigurationProperties(ServerProperties.class)
public class EmbeddedWebServerFactorycustomizerAutoconfiquration {

    @Configuration(proxyBeanMethods =false)
    @ConditionalOnclass({ Tomcat.class, UpgradeProtocol.class })
    public static class TomcatWebServerFactoryCustomizerConfiguration {
        @Bean
        public TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(Environment environment, 
                 ServerProperties serverProperties){
            return new TomcatWebServerFactoryCustomizer(environment, serverProperties);
        }
    }
}
//把配置文件中所有以"server"开头的,所以跟ServerProperties 一一对应的属性进行绑定,
//比如server.port;server.address
//属性类把配置文件绑定在类中,而且把这个类放进容器中 
//为啥要把属性类放进容器中?
//因为给容器放入Tomcat自定义工厂组件的时候,它要求传入ServerProperties 
//而@Bean的方法参数中如果容器里面有,就去容器里拿;而正好我们把属性类放入了容器
@ConfiqurationProperties(prefix="server", iqnoreUnknownFields =true)
public class ServerProperties {

    private Integer port;
    private InetAddress address;
    private String serverHeader;
    ...
}


自动配置原理2.0--spring-web版

新建一个spring-boot项目,勾选spring-web和lombok
先看依赖接结构,start-web整合了json,tomcat,web,webmvc,自动配置的功能主要在starter里的autoconfigure(依赖)里面,进去autoconfigure看看是怎么个事儿



找到包


由于项目启动时只会扫描主程序当前所在的包,上面的包是扫不到的,所以是靠主程序的@SpringBootApplication注解来实现,前面有讲这个注解的组成,由@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan组成。
@ComponentScan解决扫描包的问题,@EnableAutoConfiguration解决自动配置问题,那么它是如何把我们需要的类注册进容器中的呢?追进@EnableAutoConfiguration发现它由@Import({AutoConfigurationImportSelector.class})构成,这个注解的作用就是批量导入自动配置类。具体是怎么批量导入的呢?追进AutoConfigurationImportSelector.class,看不懂,不如设个断点调试一下,可以在上面的图看到getAutoConfigurationEntry方法里返回了自动配置类的entry,list里面有24个我们需要的自动配置类的全类名,这些类名又是如何拿到的?追进getCandidateConfigurations方法,发现它是加载了AutoConfiguration.class这个类,并且后面有个文件路径,这个路径存的就是所有自动配置类的全类名,

随便点进一个关于web的自动配置类看看,发现都有@ConditionalOnClass注解,意思是当类__存在时,才会加载这个配置类。即实现了按需加载。所以前面的list有24个而非150多个。配置类又会往容器里注册多个组件。组件里的属性都绑定在xxxProperties类中,xxxProperties类又与配置文件绑定,所以修改配置文件就能实现组件属性的修改。

posted @ 2024-03-01 23:21  不会des  阅读(71)  评论(0编辑  收藏  举报