SpringBoot 启动过程详解

SpringBoot 启动过程

SpringBoot 主要分为两大步:1、执行SpringApplication 构造;2、执行 run() 方法

1.SpringApplication 构造

SpringApplication构造源码:

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
   this.resourceLoader = resourceLoader;
   Assert.notNull(primarySources, "PrimarySources must not be null");
   this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    //推断应用类型:非 Web 应用;Web 应用,是 Servlet 类型的还是 Reactive 类型的
   this.webApplicationType = WebApplicationType.deduceFromClasspath();
   this.bootstrapRegistryInitializers = new ArrayList<>(
         getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
    //ApplicationContext 初始化器,对 ApplicationContext 做扩展
   setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    //获取监听器,对SpringBoot在执行 run() 时发布的事件进行监听和处理
   setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    //推断主类,获得当前 SpringBoot main 方法所在的类
   this.mainApplicationClass = deduceMainApplicationClass();
}
  1. 获取 Bean Definition 源,可以通过解析 xml 文件或配置类等
  2. 推断应用类型:非 Web 应用;Web 应用,是 Servlet 类型的还是 Reactive 类型的
  3. ApplicationContext 初始化器,对 ApplicationContext 做扩展
  4. 获取监听器,对SpringBoot在执行 run() 时发布的事件进行监听和处理
  5. 推断主类,获得当前 SpringBoot main 方法所在的类

2.执行 run 方法源码

主要分为 12 个步骤和 7 大事件

run 方法源码:

public ConfigurableApplicationContext run(String... args) {
		long startTime = System.nanoTime();
		DefaultBootstrapContext bootstrapContext = createBootstrapContext();
		ConfigurableApplicationContext context = null;
		configureHeadlessProperty();
    	//1.读取spring factories的配置信息,找到一个事件发布器的实现类,得到事件发布器,他是一个发布器,不是监听器
		SpringApplicationRunListeners listeners = getRunListeners(args); 
    	//发布 starting() 事件,表示spring Boot 程序开始启动
		listeners.starting(bootstrapContext, this.mainApplicationClass);
		try {
            //2.将main方法的args参数封装成ApplicationArguments对象,该对象有两类:一类是以“-”号开头的选项参数
            //第二类是:非选型参数;选项参数可以通过命令行添加到environment中
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            //3-6 步见prepareEnvironment()方法
			ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext,
                                                                     applicationArguments);
			configureIgnoreBeanInfo(environment);
            //7.打印SpringBoot启动时的图标,也就是Banner信息
			Banner printedBanner = printBanner(environment);
            //8.创建Spring容器,根据上面提到的SpringApplication的构造方法中推断出的容器类型,在三种里选择一种实现
			context = createApplicationContext();
			context.setApplicationStartup(this.applicationStartup);
            //9-10步见prepareContext()方法
        			prepareContext(bootstrapContext, context, environment, listeners, applicationArguments,
                           printedBanner);
            //11.调用ApplicationContext的refresh方法,在refresh中就会调用各种BeanFactory的后处理器
            //(BeanFactoryPostProcessor)、Bean的后处理器(BeanPostProcessor),初始化单例Bean
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(),
                                                                            timeTakenToStartup);
			}
            //发布启动完成事件,表示SpringApplicationContext准备完毕
			listeners.started(context, timeTakenToStartup);
            //第12步见callRunners()方法
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
            //如果中间出现异常,在该方法中发布启动失败事件
			handleRunFailure(context, ex, listeners);
			throw new IllegalStateException(ex);
		}
		try {
			Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
            //发布springBoot程序启动完成事件
			listeners.ready(context, timeTakenToReady);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

prepareEnvironment 方法源码:

	private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
			DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
		// Create and configure the environment
        //3.创建 environment 
		ConfigurableEnvironment environment = getOrCreateEnvironment();
        //并将前面获取的选项参数信息封装成PropertySources,添加到environment中
		configureEnvironment(environment, applicationArguments.getSourceArgs());
        //4.将environment中不同风格的键(如:有的是“_”分隔的,驼峰的,以“-“分隔的)同一转化成”-“分隔的
		ConfigurationPropertySources.attach(environment);
        //5.发布environment准备完毕事件,然后spring factories中的监听器对象,该对象会调用environment的postProcessor
        //对environment做扩展增强,添加更多的源(如:产生随机数的源、application.properties的源)
		listeners.environmentPrepared(bootstrapContext, environment);
		DefaultPropertiesPropertySource.moveToEnd(environment);
		Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
				"Environment prefix cannot be set via properties.");
        //6.把environment中所有以spring.main为前缀的键,跟springApplication对象做一个绑定
		bindToSpringApplication(environment);
		if (!this.isCustomEnvironment) {
			EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());
			environment = environmentConverter.convertEnvironmentIfNecessary(environment,
                                                                             deduceEnvironmentClass());
		}
		ConfigurationPropertySources.attach(environment);
		return environment;
	}

prepareContext源码:

	private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext 
                                context,ConfigurableEnvironment environment, SpringApplicationRunListeners
                                listeners,ApplicationArguments applicationArguments, 
                                Banner printedBanner) {
		context.setEnvironment(environment);
		postProcessApplicationContext(context);
        //9.应用初始化器,对ApplicationContext进行功能增强
		applyInitializers(context);
        //发布容器准备完毕事件
		listeners.contextPrepared(context);
		bootstrapContext.close(context);
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		// Add boot specific singleton beans
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if (printedBanner != null) {
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
			((AbstractAutowireCapableBeanFactory) beanFactory)
            .setAllowCircularReferences(this.allowCircularReferences);
			if (beanFactory instanceof DefaultListableBeanFactory) {
				((DefaultListableBeanFactory) beanFactory)
						.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
			}
		}
		if (this.lazyInitialization) {
			context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
		}
		context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
		// Load the sources
        //10.得到所有的BeanDefinition源(如:从xml中读取Bean、从配置类中获取、从组件扫描中获取)
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
        //load方法将BeanDefinition加载到容器
		load(context, sources.toArray(new Object[0]));
        //发布容器加载完成事件
		listeners.contextLoaded(context);
	}

callRunners源码:

//12.调用所有实现了ApplicationRunner、CommandLineRunner接口的Bean
private void callRunners(ApplicationContext context, ApplicationArguments args) {
		List<Object> runners = new ArrayList<>();
		runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
		runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
		AnnotationAwareOrderComparator.sort(runners);
		for (Object runner : new LinkedHashSet<>(runners)) {
			if (runner instanceof ApplicationRunner) {
				callRunner((ApplicationRunner) runner, args);
			}
			if (runner instanceof CommandLineRunner) {
				callRunner((CommandLineRunner) runner, args);
			}
		}
	}

综上,run方法执行步骤为 12 步骤和 7 大事件:

  1. 读取spring factories的配置信息,找到一个事件发布器的实现类,得到事件发布器,他是一个发布器,不是监听器
    • 发布 starting() 事件,表示spring Boot 程序开始启动
  2. 将main方法的args参数封装成ApplicationArguments对象,该对象有两类:一类是以“-”号开头的选项参数,第二类是:非选型参数;选项参数可以通过命令行添加到environment中
  3. 创建 environment ,并将前面获取的选项参数信息封装成PropertySources,添加到environment中
  4. 将environment中不同风格的键(如:有的是“_”分隔的,驼峰的,以“-“分隔的)同一转化成”-“分隔的
  5. 发布environment准备完毕事件,然后spring factories中的监听器对象,该对象会调用environment的postProcessor对environment做扩展增强,添加更多的源(如:产生随机数的源、application.properties的源)
  6. 把environment中所有以spring.main为前缀的键,跟springApplication对象做一个绑定
  7. 打印SpringBoot启动时的图标,也就是Banner信息
  8. 创建Spring容器,根据上面提到的SpringApplication的构造方法中推断出的容器类型,在三种里选择一种实现
  9. 应用初始化器,对ApplicationContext进行功能增强
    • 发布容器准备完毕事件
  10. 得到所有的BeanDefinition源(如:从xml中读取Bean、从配置类中获取、从组件扫描中获取),load方法将BeanDefinition加载到容器
    • 发布容器加载完成事件
  11. 调用ApplicationContext的refresh方法,在refresh中就会调用各种BeanFactory的后处理器(BeanFactoryPostProcessor)、Bean的后处理器(BeanPostProcessor),初始化单例Bean
    • 发布启动完成事件,表示SpringApplicationContext准备完毕
  12. 调用所有实现了ApplicationRunner、CommandLineRunner接口的Bean
    • 发布springBoot程序启动完成事件
    • 如果中间出现异常,在handleRunFailure() 方法中发布启动失败事件
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值