SpringBoot启动流程源码分析( 六 )

复制
预备环境其实就做了下面几件事情:

  • 创建一个ConfigurableEnvironment类型的配置环境
  • 将配置环境实例ConfigurableEnvironment与SpringApplication启动类实例绑定到一个Binder对象中去
  • 上一步的 绑定属性的过程会去解析属性占位符 , 并按照配置环境配置的转换服务转转绑定结果 , 如果绑定成功或失败都会有对应的事件处理方法
创建Spring应用上下文现在我们回到SpringApplication#run方法的context = this.createApplicationContext();这行代码的具体实现 , 进入SpringApplication#createApplicationContext方法体 , 源码如下:
protected ConfigurableApplicationContext createApplicationContext() {Class<?> contextClass = this.applicationContextClass;if (contextClass == null) {// 若启动类的应用上下文为空 , 则根据实例化SpringApplication启动类过程中推断出来的web应用类型加载对应的应用上下文类ApplicationContexttry {switch(this.webApplicationType) {case SERVLET:contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");break;case REACTIVE:contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");break;default:contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");}} catch (ClassNotFoundException var3) {throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);}}return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);}复制
从以上的源码可以看出创建应用上下文过程主要做了下面两件事情:
  1. 根据web应用类型加载对应的ApplicationContext实现类:
  • 如果是Servlet应用程序则加载AnnotationConfigServletWebServerApplicationContext类作为应用上下文类;
  • 如果是Reactive应用程序则加载AnnotationConfigReactiveWebServerApplicationContext类作为应用上下文类;
  • 默认加载AnnotationConfigApplicationContext类作为应用上下文类
  1. 调用BeanUtils工具类实例化应用上下文类 , 并返回这个实例化的应用上下文对象
准备Spring应用上下文接下来我们再回到SpringApplication#run方法的this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);这行代码 , 并进入SpringApplication#prepareContext方法体内部
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 , 注意该类是个接口类ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();// 注册启动参数类型单例beanbeanFactory.registerSingleton("springApplicationArguments", applicationArguments);if (printedBanner != null) {// 注册PrintedBanner类型单例beanbeanFactory.registerSingleton("springBootBanner", printedBanner);}// 判断应用上下文中的beanFactory是否是一个DefaultListableBeanFactory类型的实例if (beanFactory instanceof DefaultListableBeanFactory) {((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);// 设置是否允许覆写bean定义标识}if (this.lazyInitialization) {// 若是延迟初始化 , 则添加延迟初始化类型beanFactory后置处理器context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());}// 获取启动来源类集合 , 也就是我们项目中加上@SpringBootApplication注解的启动类集合Set<Object> sources = this.getAllSources();// 断言启动来源类不为空Assert.notEmpty(sources, "Sources must not be empty");// 加载应用上下文 , 这个方法会通过beanDefinationReader读取通过注解和xml配置的beanthis.load(context, sources.toArray(new Object[0]));// 启动监听器发布上下文完成加载事件listeners.contextLoaded(context);}

经验总结扩展阅读