springBoot学习笔记-04-SpringBoot自动装配原理


自动装配原理.

POM.xml.

核心依赖 在父工程中(含有大量的依赖)

  • 核心依赖:spring-boot-dependencies
    • 其子依赖:spring-boot-starter-parent
      • 项目依赖:springbootstudy

启动器.

Spring Boot的启动场景

  • 需要什么功能,就使用相应的启动器
    • 如spring-boot-starter-web 会帮我们自动导入web环境所需要的所有依赖

更多:https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter

主程序.

注解:.

1、表面理解:

@SpringBootApplication —— 启动类标志

2、接下来深入理解

进入@SpringBootApplication注解内部 可以看到其内部又包含了3个注解,与配置有关的就是 @SpringBootConfiguration@EnableAutoConfiguration

3、这两注解内部结构基本如下:

@SpringBootConfiguration
    @Configuration // 说明 这个类是一个配置类(类似于Spring中xml配置文件)
        @Component // 说明 这个类也是一个组件 -- 因此 可以被上面@ComponentScan扫描到

@EnableAutoConfiguration // 自动配置
    @AutoConfigurationPackage  //  自动配置包
        @Import(AutoConfigurationPackages.Registrar.class) // 自动配置包注册
    @Import(AutoConfigurationImportSelector.class) // 自动配置导入选择:获取所有的配置

4、看到以上结构,我们知道SpringBoot的自动配置,目前只涉及到两个类

AutoConfigurationPackages.Registrar : 包注册

Registrar.class 作用:将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器

AutoConfigurationImportSelector :导入候选的配置类 (重点

AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);

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

加载了 EnableAutoConfiguration 对应的配置类 – 详情看后面 (META-INF/spring.facotories中对应的)

// 核心语句
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
                getBeanClassLoader());

以下是可以被导入的配置类,如果没有,那么需要自定义配置

spring.factories文件内容

着重关注这个类

可以得出结论:所有的自动配置类都是在启动的时候被扫描并导入到容器(spring.factories中的自动配置类—— 全限定名形式 xxxAutoConfiguration,但是并不是都生效,看是否有对应的启动器(会涉及到新的注解)

①启动时,加载 spring.factories文件中的 自动配置类,导入到容器中

②当然,需要对应的启动器才生效

xxxAutoConfIguration会导入其相关的组件(@Bean),并自动配置,免去我们手动编写的配置文件的工作

5、从以上我们知道了自动加载的配置类有哪些,但是实际上,并没有全部有效,为什么呢?

那么就涉及到 新的注解 @ConditionalXXX 满足某些条件就加载,比如说有某个类(一般在启动器中)的时候生效

运行 Run.

查看构造器,SpringApplication做了如下4个事情:

  • 推断应用的类型是普通还是Web
  • 查找所有的应用程序监听器,设置到initializers属性中
  • 找出所有的应用程序监听器,设置到listeners属性中
  • 推断并设置main方法的定义类,找到运行的主类
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
   this.resourceLoader = resourceLoader;
   Assert.notNull(primarySources, "PrimarySources must not be null");
   this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
   this.webApplicationType = WebApplicationType.deduceFromClasspath();
   setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
   setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
   this.mainApplicationClass = deduceMainApplicationClass();
}
run方法流程分析.

该图来自狂神说Java,https://blog.csdn.net/qq_33369905/article/details/106647293

public ConfigurableApplicationContext run(String... args) {
   StopWatch stopWatch = new StopWatch();
   stopWatch.start();
   ConfigurableApplicationContext context = null;
   Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
   configureHeadlessProperty();
   SpringApplicationRunListeners listeners = getRunListeners(args);
   listeners.starting();
   try {
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
      ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
      configureIgnoreBeanInfo(environment);
      Banner printedBanner = printBanner(environment);
      context = createApplicationContext();
      exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
            new Class[] { ConfigurableApplicationContext.class }, context);
      prepareContext(context, environment, listeners, applicationArguments, printedBanner);
      refreshContext(context);
      afterRefresh(context, applicationArguments);
      stopWatch.stop();
      if (this.logStartupInfo) {
         new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
      }
      listeners.started(context);
      callRunners(context, applicationArguments);
   }
   catch (Throwable ex) {
      handleRunFailure(context, ex, exceptionReporters, listeners);
      throw new IllegalStateException(ex);
   }

   try {
      listeners.running(context);
   }
   catch (Throwable ex) {
      handleRunFailure(context, ex, exceptionReporters, null);
      throw new IllegalStateException(ex);
   }
   return context;
}

文章作者: liuminkai
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 liuminkai !
评论
 上一篇
springBoot学习笔记-05-SpringBoot配置 springBoot学习笔记-05-SpringBoot配置
SpringBoot配置. https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/ 配置文件格式 application.properties key
2020-09-12
下一篇 
springBoot学习笔记-03-第一个SpringBoot程序 springBoot学习笔记-03-第一个SpringBoot程序
创建第一个SpringBoot程序.一、创建工程.方式一(Spring Boot 官方网站). https://spring.io/projects/spring-boot/ 然后下载压缩包,解压,导入项目(maven)即可 方式二(
2020-09-09
  目录