spring boot 启动和自动装配原理

126 阅读1分钟

spring boot 启动过程

启动流程图

image.png

  1. 启动程序入口
public static void main(String[] args) {
   SpringApplication.run(WebApplication02.class, args);
}

  1. SpringApplication run 方法
...省略部分代码

public ConfigurableApplicationContext run(String... args) {
   StopWatch stopWatch = new StopWatch();
   stopWatch.start();
   ConfigurableApplicationContext context = null;
   Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
   configureHeadlessProperty();
   //反射的方式加载SpringApplicationRunListeners 实例
   SpringApplicationRunListeners listeners = getRunListeners(args);
   
   // 调用监听starting()
   listeners.starting();
   
   try {
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
      //配置环境
      ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
      configureIgnoreBeanInfo(environment);
      
      //banner
      Banner printedBanner = printBanner(environment);
      
     //创建context,实例有
    //AnnotationConfigApplicationContext
    //AnnotationConfigReactiveWebServerApplicationContext
    //AnnotationConfigServletWebServerApplicationContext
      context = createApplicationContext();
      
      exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
            new Class[] { ConfigurableApplicationContext.class }, context);
       // 关联context environment listeners
      prepareContext(context, environment, listeners, applicationArguments, printedBanner);
      
      //启动spring context
      refreshContext(context);
      
      //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;
}

...省略部分代码

启动入口

image.png

核心注解

  • @SpringBootApplication

image.png

  • @SpringBootConfiguration

等价@Configuration,@Configuration + @Bean = bean定义(可以理解为xml bean 声明)

image.png

  • @EnableAutoConfiguration

spring boot 自动装配,其中AutoConfigurationImportSelector.class为spring boot spi 装载的核心

image.png

  • @ComponentScan

spring boot 包扫描 如果不指定默认从声明@ComponentScan 开始扫描

spring boot 自动装配配置类

spring boot 自动状态核心类

AutoConfigurationImportSelector.class

image.png

SpringFactoriesLoader.class 从spring.factories 文件中加载 Bean

image.png

//加载bean 配置
public String[] selectImports(AnnotationMetadata annotationMetadata) {
    if (!this.isEnabled(annotationMetadata)) {
        return NO_IMPORTS;
    } else {
        AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
        AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
        return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    }
}


protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, 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.filter(configurations, autoConfigurationMetadata);
        this.fireAutoConfigurationImportEvents(configurations, exclusions);
        return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
    }
}


protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//SpringFactoriesLoader 读spring.facotories 文件
    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;
}

自动装配常用的几个注解

  • @ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class})这个注解的意思是:当存在SqlSessionFactory.class, SqlSessionFactoryBean.class这两个类时才解析MybatisAutoConfiguration配置类,否则不解析这一个配置类,make sence,我们需要mybatis为我们返回会话对象,就必须有会话工厂相关类。

  • @CondtionalOnBean(DataSource.class):只有处理已经被声明为bean的dataSource。

  • @ConditionalOnMissingBean(MapperFactoryBean.class)这个注解的意思是如果容器中不存在name指定的bean则创建bean注入,否则不执行(该类源码较长,篇幅限制不全粘贴)

参考博客