SpringApplication 构造方法
this.webApplicationType = WebApplicationType.deduceFromClasspath(); this.bootstrapRegistryInitializers = new ArrayList<>( getSpringFactoriesInstances(BootstrapRegistryInitializer.class)); setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); // 把项目启动类.class设置为属性存储起来 this.primarySources = new LinkedHashSet(Arrays.asList(primarySources)); // 判断当前webApplicationType应用的类型 this.webApplicationType = WebApplicationType.deduceFromClasspath(); this.bootstrapRegistryInitializers = new ArrayList<>( getSpringFactoriesInstances(BootstrapRegistryInitializer.class)); // 设置初始化器(Initializer),最后会调用这些初始化器 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 设置监听器(Listener) setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 用于推断并设置项目main()方法启动的主程序启动类 this.mainApplicationClass = this.deduceMainApplicationClass();
解释说明:
-
this.webApplicationType = WebApplicationType.deduceFromClasspath()
用于判断当前webApplicationType应用的类型。deduceFromClasspath()方法用于查看Classpath类路径下是否存在某个特征类,从而判断当前webApplicationType类型是SERVLET应用(Spring5之前的传统MVC应用)还是REACTIVE应用(Spring5之后的WebFlux交互式应用)。
-
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)
用于SpringApplication应用的初始化器设置。在初始化器设置过程中,会使用Spring类加载器SpringFactoriesLoader从META-INF类路径下的spring.factories文件中获取所有可用的应用初始化器类ApplicationContextInitializer。
-
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class))
用于SpringApplication应用的监听器设置。监听器设置的过程与上一步初始化器设置的过程基本一样,也是使用SpringFactoriesLoader从META-INF类路径下的spring.factories文件中获取所有可用的监听器类ApplicationListener。
-
this.mainApplicationClass = this.deduceMainApplicationClass()
用于推断并设置项目main()方法启动的主程序启动类。
run 方法
-
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
创建独立的上下文
-
configureHeadlessProperty();
检测是否有显示器,对于服务器程序来说,这个不重要,有没有显示器都能正常运行
-
SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(bootstrapContext, this.mainApplicationClass);
获取SpringApplication实例初始化过程中 初始化的SpringApplicationRunListener监听器并运行。
-
this.prepareEnvironment(listeners, applicationArguments);
对项目环境进行预设
-
configureIgnoreBeanInfo(environment);
排除一些不需要的运行环境
-
context = createApplicationContext();
创建Spring IOC容器,根据webApplicationType进行判断,确定容器类型,如果该类型为SERVLET类型,会通过反射加载对应的字节码,也就是AnnotationConfigServletWebServerApplicationContext
-
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
在容器刷新之前的准备动作,使用之前初始化设置的context(应用上下文环境)、environment(项目运行环境)、listeners(运行监听器)、applicationArguments(项目参数)和 printedBanner(项目图标信息)进行上下文的组装配置。其中包含一个非常关键的操作:将启动类注入容器,为后续开启自动化配置奠定基础。
-
refreshContext(context);
开启刷新Spring容器,通过refresh方法对整个IOC容器的初始化(包括bean资源的定位、解析、注册等等),同时向JVM运行时注册一个关机钩子(shutdown hook),在JVM关机时会关闭这个上下文,除非当时它已经关闭。自动装配就是在这里生效的。
-
afterRefresh(context, applicationArguments);
Spring容器后置处理,扩展接口,设计模式中的模板方法,默认为空实现
-
listeners.started(context, timeTakenToStartup);
获取EventPublishingRunListener监听器,并执行其started方法,并且将创建的Spring容器传送进去,创建一个ApplicationStartedEvent事件,并执行ConfigurableApplicationContext的publishEvent方法,也就是说这里是在Spring容器中发布事件,并不是在SpringApplication中发布事件,和前面的starting是不同的,前面的starting是直接向SpringApplication中的监听器发布启动事件
-
callRunners(context, applicationArguments);
用于调用项目中自定义的执行器XxxRunner类,使得在项目启动完成后立即执行一些特定程序。其中,SpringBoot提供的执行器接口有ApplicationRunner和CommandLineRunner两种,在使用时只需要自定义一个执行器类实现其中一个接口并重写对应的run()方法接口,然后SpringBoot项目启动后立即执行这些特定程序。