1、总体步骤分两个
创建Spring 应⽤(创建SpringApplication)运⾏Spring 应⽤(运⾏SpringApplication)
2、创建Spring 应⽤(创建SpringApplication)
就是new ⼀个对象,构造器⾥⾯做⼀些初始化的动作
public SpringApplication(ResourceLoader resourceLoader, Class>... primarySources) { this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, \"PrimarySources must not be null\");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); //判断应⽤的类型deduce v. 推论; 推断; 演绎;的意思
this.webApplicationType = WebApplicationType.deduceFromClasspath(); //设置初始化器,保存起来 从spring.factories 找
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); //设置监听器、保存起来从spring.factories 找
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); //主应⽤类是那个
this.mainApplicationClass = deduceMainApplicationClass(); }
3、运⾏Spring 应⽤(运⾏SpringApplication)
// args 就是我们java-jar 时传的命令⾏参数
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start();
ConfigurableApplicationContext context = null;
Collection //获取所有的运⾏监听器:就⼀个EventPublishingRunListener从spring.factories 中找的 SpringApplicationRunListeners listeners = getRunListeners(args); //通知对系统启动过程中的⼈,项⽬正在启动,让所有的监听器感知到项⽬正在启动,这⾥就包括我们⾃⼰定义的监听器 listeners.starting(); try { //保存我们传过来的命令⾏参数 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); //准备环境, ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); //创建IOC容器,这⾥⾄关重要。这个没有特别的,根绝应⽤的类型来创建⼀个SERVLET容器 context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); //准备ioc 容器 prepareContext(context, environment, listeners, applicationArguments, printedBanner); //刷新ioc 容器 refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } //通知所有的监听器应⽤启动完成了 listeners.started(context); //获取容器中的ApplicationRunner 和CommandLineRunner ,然后遍历所有的runner,执⾏runner的run⽅法,runner⼀般都是我们⾃⼰写的 callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { //调⽤所有监听器的running ⽅法,对程序运⾏过程进⾏监听。 listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context;} 3.1 prepareEnvironment ⽅法说明 在这⼀步,SpringApplication会创建Spring启动所需的环境,这个环境主要由ConfigurableEnviroment对象表⽰。 ⾸先,该对象确认了程序是否需要设置Web环境,其次,该对象还确定了程序所需要的参数和读取的配置⽂件等信息。 /** * * 获取或者创建⼀个Environment对象,如果我们⾃⼰在main ⽅法⾥⾯创建了⼀个Environment,并放到 * SpringApplication 中了就不创建了, * SpringApplication application = new SpringApplication(ProfileDemoApplication.class); * ConfigurableEnvironment environment = new StandardEnvironment(); * environment.setActiveProfiles(\"dev\"); * application.setEnvironment(environment); * 否则就创建 * * */ 注意:以下的说明 // 添加初始的properties(注意:当前并未加载如application.properties/yml的properties)// 添加初始的profile(注意:当前并未加载如application.properties/yml配置profile) private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { //创建或者获取⼀个Environment 对象 ConfigurableEnvironment environment = getOrCreateEnvironment(); //配置environment configureEnvironment(environment, applicationArguments.getSourceArgs()); ConfigurationPropertySources.attach(environment); // 触发监听器(主要是触发ConfigFileApplicationListener,这个监听器将会加载如application.properties/yml这样的配置⽂件) //通知所有的监听器环境准备好了,包括我门⾃⼰定义的监听器。 listeners.environmentPrepared(environment); bindToSpringApplication(environment); if (!this.isCustomEnvironment) { environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass()); } return environment; } 3.1.1 configureEnvironment //配置环境 protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) { if (this.addConversionService) { ConversionService conversionService = ApplicationConversionService.getSharedInstance(); environment.setConversionService((ConfigurableConversionService)conversionService); } //把命令⾏参数、外部配置⽂件的属性(利⽤@PropertySource指定的⽂件),系统属性都配置到环境⾥⾯、加载配置⽂件 this.configurePropertySources(environment, args); //激活profile环境的 this.configureProfiles(environment, args); } 3.2 prepareContext /** * * * 虽然已经得到了ApplicationContext对象,但此时的对象还只是⼀个空⽩对象,需要准备和处理后,ApplicationContext才能被使⽤。 * * 在准备过程中主要做了做了⼏件事: * 为ApplicationContext设置之前准备好的Environment对象、也就是说把Environment 组件放到容器⾥⾯ * * 通过对ApplicationContext后置处理或是BeanDefinitionLoader等⽅式往容器中添加⼀些初始的Bean。 * * 应⽤默认的初始化器初始化应⽤程序上下⽂(责任链模式的应⽤,多个初始化器形成⼀个List,应⽤程序需要被每个初始化器应⽤⼀次,每个初始化器有⾃⼰的职责)。 * * 准备过程中ApplicationRunListener发出两个消息,分别是contextPrepared和contextLoaded。 */ private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { // 给上下⽂对象设置环境对象,给AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner设置环境对象 context.setEnvironment(environment); // 1. 上下⽂后置处理,包括向BeanFactory中注册BeanNameGenerator和ConversionService postProcessApplicationContext(context); // 2. SpringApplication构造器中初始化了各种ApplicationContextInitializer(应⽤初试化器), //循环调⽤他们的initialize⽅法、对ioc 容器进⾏扩展 applyInitializers(context); // 遍历所有的监听器,通知监听器上下⽂准备好了。 listeners.contextPrepared(context); if (this.logStartupInfo) { // 打印启动信息,包括pid,⽤户等 logStartupInfo(context.getParent() == null); // 答应profile信息 logStartupProfileInfo(context); } // Add boot specific singleton beans ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); // 将命令⾏参数组件注册到容器⾥⾯ beanFactory.registerSingleton(\"springApplicationArguments\ if (printedBanner != null) { // 将Banner注册到容器中 beanFactory.registerSingleton(\"springBootBanner\ } if (beanFactory instanceof DefaultListableBeanFactory) { // 设置不允许定义同名的BeanDefinition,重复注册时抛出异常 ((DefaultListableBeanFactory) beanFactory) .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } if (this.lazyInitialization) { // 如果懒加载,添加懒加载后置处理器 context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()); } // Load the sources Set