springBoot学习笔记源码分析之springApplication初始化过程
Posted 拐柒
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springBoot学习笔记源码分析之springApplication初始化过程相关的知识,希望对你有一定的参考价值。
springBoot学习笔记(三)源码分析之springApplication初始化过程
SpringApplication
springboot 启动的main放中的SpringApplication.run(DemoApplication.class, args)中的run方法其实是调用了SpringApplication中的run方法。
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
该方法分为两部分,第一部分为初始化SpringApplication,第二部分为run
初始化SpringApplication
//将resourceLoader 置为null
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
//把启动类applicaiton放入成员变量名为primarySources的set中
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
//推断应用类型,后面会根据该变量初始化对应的环境,一般为servlet
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//初始化classpah下META-INF/spring.factory中已配置的ApplicaitonContextInitializer,通过反射进行初始化器的初始化。ApplicaitonContextInitializer是spring提供的一个接口,其作用spring容器在刷新之前,会回调initialize方法。
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
//初始化classpah下META-INF/spring.factory中已配置的ApplicationListener,通过反射进行监听器的初始化。ApplicationListener可以对spring进行全生命周期的监听
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
//根据调用栈,推断出main方法的类名
this.mainApplicationClass = this.deduceMainApplicationClass();
1、推断应用类型,一般为servlet。
2、初始化ApplicaitonContextInitializer初始化器。
3、初始化监听器
4、获取main方法类名。
run方法
public ConfigurableApplicationContext run(String... args) {
//记录程序运行时间
StopWatch stopWatch = new StopWatch();
stopWatch.start();
DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
//ConfigurableApplicationContext spring的上下文
ConfigurableApplicationContext context = null;
this.configureHeadlessProperty();
//1、获取并启动监听器
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//2、构造应用上下文环境
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
this.configureIgnoreBeanInfo(environment);
Banner printedBanner = this.printBanner(environment);
//3、初始化应用上下文
context = this.createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
//4、刷新应用上下文前的准备阶段
this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
//5、刷新应用上下文
this.refreshContext(context);
//6、刷新应用上下文后的拓展接口
this.afterRefresh(context, applicationArguments);
//记录时间停止
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
listeners.started(context);
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, listeners);
throw new IllegalStateException(var10);
}
try {
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
获取并启动监听器
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
//springApplicaitonRunListeners负责在springboot启动的不同阶段,广播出不同的消息,传递信息给ApplicationListener监听器实现类
return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args), this.applicationStartup);
}
构造应用上下文环境
应用上下文环境:上下文,上下文代表了程序当下所运行的环境,联系你整个app的生命周期与资源调用,是程序可以访问到的所有资源的总和,资源可以是一个变量,也可以是一个对象的引用。
prepareEnvironment
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
//创建并配置相应环境
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
//根据用户配置,配置environment系统环境,通过判断应用类型,即SERVLET,来创建环境
this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach((Environment)environment);
//启动相应的监听器,其中一个重要的监听器ConfigFileApplicationListener就是加载项目配置文件的监听器
listeners.environmentPrepared(environment);
this.bindToSpringApplication((ConfigurableEnvironment)environment);
if (!this.isCustomEnvironment) {
environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
}
ConfigurationPropertySources.attach((Environment)environment);
return (ConfigurableEnvironment)environment;
}
初始化应用上下文
beanFactory正是在AnnotationConfigServletWebServerApplicationContext实现的接口
GenericApplicationContext中定义的。在上面createApplicationContext()方法中的,
BeanUtils.instantiateClass(contextClass) 这个方法中,不但初始化了
AnnotationConfigServletWebServerApplicationContext类,也就是我们的上下文context,同样
也触发了GenericApplicationContext类的构造函数,从而IoC容器也创建了。
刷新应用上下文前的准备阶段
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
//设置容器环境
context.setEnvironment(environment);
//执行容器后置处理
postProcessApplicationContext(context);
//执行容器中的 ApplicationContextInitializer 包括spring.factories和通过三种 方式自定义的
applyInitializers(context);
//向各个监听器发送容器已经准备好的事件
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
//将main函数中的args参数封装成单例Bean,注册进容器
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());
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
//加载启动类,将启动类注入容器
load(context, sources.toArray(new Object[0]));
//发布容器已加载事件
listeners.contextLoaded(context);
}
刷新应用上下文(IOC容器的初始化过程)
主要是执行AbstractApplicationContext类的refresh()方法。
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
//刷新上下文环境
this.prepareRefresh();
//这里是在子类中启动refreshBeanFactory()的地方
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
//准备bean工厂,以便在此上下文中使用
this.prepareBeanFactory(beanFactory);
try {
//设置beanFactory的后置处理
this.postProcessBeanFactory(beanFactory);
//调用BeanFactory的后处理器,这些处理器是在Bean定义中向容器注册的
this.invokeBeanFactoryPostProcessors(beanFactory);
//注册Bean的后处理器,在Bean创建过程中调用
this.registerBeanPostProcessors(beanFactory);
//对上下文中的消息源进行初始化
this.initMessageSource();
//初始化上下文中的事件机制
this.initApplicationEventMulticaster();
//初始化其他特殊的Bean
this.onRefresh();
//检查监听Bean并且将这些监听Bean向容器注册
this.registerListeners();
//实例化所有的(non-lazy-init)单件
this.finishBeanFactoryInitialization(beanFactory);
//发布容器事件,结束Refresh过程
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
以上是关于springBoot学习笔记源码分析之springApplication初始化过程的主要内容,如果未能解决你的问题,请参考以下文章
我的第一个spring boot程序(spring boot 学习笔记之二)
SpringBoot 学习笔记 -- [spring Boot配置文件之YAML格式, springBoot自动配置浅入,springboot集成JDBC]