SpringBoot启动运行原理

几个重要的事件回调机制

ApplicationContextInitializer、SpringApplicationRunListener(配置在META-INF/spring.factories)

ApplicationRunner、CommandLineRunner(只需要放在ioc容器中)

启动流程

1、创建SpringApplication对象

  • this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)):从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer
  • this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)):从类路径下找到META-INF/spring.factories配置的所有ApplicationListener    
  • this.mainApplicationClass = this.deduceMainApplicationClass():从多个配置类中找到有main方法的主配置类
@SpringBootApplication
@EnableDiscoveryClient
@EnableTransactionManagement // 开启事务
@MapperScan("com.ww.ideaapp.coupon.dao")
public class IdeaCouponApplication {

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

}

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
    return run(new Class[]{primarySource}, args);
}


public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    return (new SpringApplication(primarySources)).run(args);
}

public SpringApplication(Class... primarySources) {
    this((ResourceLoader)null, primarySources);
}

public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
    this.sources = new LinkedHashSet();
    this.bannerMode = Mode.CONSOLE;
    this.logStartupInfo = true;
    this.addCommandLineProperties = true;
    this.addConversionService = true;
    this.headless = true;
    this.registerShutdownHook = true;
    this.additionalProfiles = new HashSet();
    this.isCustomEnvironment = false;
    this.lazyInitialization = false;
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
    this.webApplicationType = WebApplicationType.deduceFromClasspath();    
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); //从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer;然后保存起来
    this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); //从类路径下找到META-INF/spring.factories配置的所有ApplicationListener
    this.mainApplicationClass = this.deduceMainApplicationClass(); //从多个配置类中找到有main方法的主配置类
}

2、运行run方法

  1. 创建 StopWatch (StopWatch 主要用于简单统计 run 启动过程的时长)对象,并启动。
  2. 准备异常报告器:Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();  
  3. 设置系统属性 java.awt.headless,这里设置为 true,表示运行在服务器端,在没有显示器和鼠标键盘的模式下工作,模拟输入输出设备功能:this.configureHeadlessProperty();
  4. 从类路径下 META-INF/spring.factories 获取SpringApplicationRunListeners:SpringApplicationRunListeners listeners = this.getRunListeners(args);
  5. 调用所有的获取SpringApplicationRunListener.starting()方法:listeners.starting();
  6. 封装命令行参数:ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
  7. 准备环境:ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
  8. 环境准备完成:SpringApplicationRunListener.environmentPrepared();
  9. 打印控制台:Banner printedBanner = this.printBanner(environment);
  10. 创建 ApplicationContext;决定创建 web 的 ioc 还是普通的 ioc:context = this.createApplicationContext();
  11. 准备上下文环境,将environment保存到ioc中,而且applyInitializers();
    applyInitializers():回调之前保存的所有的ApplicationContextInitializer的initialize方法,回调所有的SpringApplicationRunListener的contextPrepared():this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
  12. 刷新容器,ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat)。Spring注解版
    扫描,创建,加载所有组件的地方(配置类,组件,自动配置):this.refreshContext(context);
  13. 再一次刷新应用上下文,表示上下文被刷新后调用,这是一个空方法,主要是为做一些上下刷新后的拓展备用:this.afterRefresh(context, applicationArguments);
  14. 停止计时:stopWatch.stop();
  15. 输出日志记录执行主类名、时间信息。                                                                                      if (this.logStartupInfo) {
                    (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
                }
  16. 发布应用上下文启动完成事件:listeners.started(context);
  17. 从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调ApplicationRunner先回调,CommandLineRunner再回调:this.callRunners(context, applicationArguments);
  18. 发布应用上下文就绪事件:listeners.running(context);
  19. 整个SpringBoot应用启动完成以后返回启动的ioc容器:return context;
public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null; // IOC容器
        // 准备异常报告器
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        this.configureHeadlessProperty();
        SpringApplicationRunListeners listeners = this.getRunListeners(args); //获取SpringApplicationRunListeners;从类路径下META-INF/spring.factories
        listeners.starting(); //回调所有的获取SpringApplicationRunListener.starting()方法

        Collection exceptionReporters;
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); //封装命令行参数
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); //准备环境,创建环境完成后回调
SpringApplicationRunListener.environmentPrepared();// 表示环境准备完成
            this.configureIgnoreBeanInfo(environment);
            Banner printedBanner = this.printBanner(environment); // 打印控制台
            context = this.createApplicationContext(); //创建ApplicationContext;决定创建web的ioc还是普通的ioc
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
            /**
	         * 准备上下文环境;将environment保存到ioc中;而且applyInitializers();
             * applyInitializers():回调之前保存的所有的ApplicationContextInitializer的initialize方法
             * 回调所有的SpringApplicationRunListener的contextPrepared();
	         */
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); //prepareContext运行完成以后回调所有的SpringApplicationRunListener的contextLoaded();
            /**
             * 刷新容器;ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat);Spring注解版
             * 扫描,创建,加载所有组件的地方;(配置类,组件,自动配置)
             */
            this.refreshContext(context);
            /**
             * 再一次刷新应用上下文,表示上下文被刷新后调用,这是一个空方法,主要是为做一些上下刷新后的拓展备用
             */
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            // 输出日志记录执行主类名、时间信息
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }
            // 发布应用上下文启动完成事件
            listeners.started(context);
            /**
             * 从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调
             * ApplicationRunner先回调,CommandLineRunner再回调
             */
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, exceptionReporters, listeners);
            throw new IllegalStateException(var10);
        }

        try {
            // 发布应用上下文就绪事件
            listeners.running(context);
            return context; //整个SpringBoot应用启动完成以后返回启动的ioc容器;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }

/**
 * 准备上下文环境;将environment保存到ioc中;而且applyInitializers();
 * applyInitializers():回调之前保存的所有的ApplicationContextInitializer的initialize方法
 * 回调所有的SpringApplicationRunListener的contextPrepared();
 */
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
        context.setEnvironment(environment);
        this.postProcessApplicationContext(context);
        this.applyInitializers(context);
        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
            this.logStartupInfo(context.getParent() == null);
            this.logStartupProfileInfo(context);
        }

        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
        if (printedBanner != null) {
            beanFactory.registerSingleton("springBootBanner", printedBanner);
        }

        if (beanFactory instanceof DefaultListableBeanFactory) {
            ((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }

        if (this.lazyInitialization) {
            context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
        }

        Set<Object> sources = this.getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        this.load(context, sources.toArray(new Object[0]));
        listeners.contextLoaded(context);
    }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值