public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
run方法
public ConfigurableApplicationContext run(String... args) {
//创建一个StopWatch对象,开始记录run()启动过程时长;
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//1.创建应用监听器并启动
//从META-INF/spring.factories文件中获取监听器 -SpringApplicationRunListener
//径下的 META-INF/spring.factories文件中找 对应SpringApplicationRunListener的全路径数组,并通过createSpringFactoriesInstances()方法实例化成对象返回;
SpringApplicationRunListeners listeners = getRunListeners(args);
//启动监听器 回调之前获得的所有SpringApplicationRunListener对象的starting()方法,启动监听
listeners.starting();
try {
// 获取命令行参数如 --server.port 等
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//2. 创建运行环境environment,创建当前SpringBoot应用要使用的environment
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
//打印Banner,也可以自定义启动logo,比如在resources路径下创建一个banner.txt文件,将你想打印的图标放入其中
Banner printedBanner = printBanner(environment);
//3 创建ApplicationContext容器,根据类型决定是创建普通WEB容器还是REACTIVE容器还是普通Annotation的ioc 容器
context = createApplicationContext();
//获取异常报告器SpringBootExceptionReporter
//
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//从initializers集合中遍历所有的ApplicationContextInitializer,并通过initializer.initialize( )方法初始化
//4.Spring容器前置处理
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//5. 刷新容器
refreshContext(context);
//6.spring容器后置处理
afterRefresh(context, applicationArguments);
//计时结束
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
//7.发布结束执行通知
listeners.started(context);
//8.执行Runners
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
//如果有异常就抛出
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
//9.发布应用上下文就绪事件
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
1-getRunListeners
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
- getSpringFactoriesInstances 最终调用
org.springframework.core.io.support.SpringFactoriesLoader#loadSpringFactories
public static final String FACTORIES_RESOURCE_LOCATION = “META-INF/spring.factories”;
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
//META-INF/spring.factories从文件中获取指定类型的并最后实例化
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
2. prepareEnvironment
准备环境
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
switch (this.webApplicationType) {
case SERVLET:
return new StandardServletEnvironment();
case REACTIVE:
return new StandardReactiveWebEnvironment();
default:
return new StandardEnvironment();
}
}
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
//创建一个environment对象
ConfigurableEnvironment environment = getOrCreateEnvironment();
//配置环境 PropertySources Profiles
configureEnvironment(environment, applicationArguments.getSourceArgs());
//PropertySources
ConfigurationPropertySources.attach(environment);
//环境准备
listeners.environmentPrepared(environment);
//将环境绑定到oSpringApplication(
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
//配置PropertySources-如果有attach到environment
ConfigurationPropertySources.attach(environment);
return environment;
}
3.createApplicationContext();
protected ConfigurableApplicationContext createApplicationContext() {
//获取上下文的类
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
//判断Web应用类型
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
4.prepareContext
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
//上下文设置环境
context.setEnvironment(environment);
//处理上下文,Bean的生成器和资源加载器
postProcessApplicationContext(context);
//从initializers集合中遍历所有的ApplicationContextInitializer,并通过initializer.initialize( )方法初始化
applyInitializers(context);
//回调SpringApplicationRunListener对象的contextPrepared()方法,表示容器已准备
listeners.contextPrepared(context);
//启动日志
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
//注册启动参数的Bean,将容器指定的参数封装为Bean,注入容器中
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
//是否为延迟加载 是就添加LazyInitializationBeanFactoryPostProcessor
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]));
//触发所有SpringApplicationRunListeners的contextLoaded事件方法
listeners.contextLoaded(context);
}
5.refreshContext就是去
org.springframework.context.support.AbstractApplicationContext#refresh
private void refreshContext(ConfigurableApplicationContext context) {
//去Spring IOC容器完成Bean的生命周期
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
6.afterRefresh 空方法
protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
}
可以自已写一些扩展
7.listeners.started(context);
void started(ConfigurableApplicationContext context) {
//获取SpringApplicationRunListener 所有监听器,循环启动
for (SpringApplicationRunListener listener : this.listeners) {
listener.started(context);
}
}
8.callRunners
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
//获取所有ApplicationRunner接口的实现类 默认没有实现
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
//获取所有CommandLineRunner --默认没有实现
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);
}
}
}
private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
try {
//运行
(runner).run(args);
}
catch (Exception ex) {
throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
}
}
9.发布应用上下文就绪事件 listeners.running(context);
listeners.running(context);
void running(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
//获取SpringApplicationRunListener 类型的所有监听器 发布事件ApplicationReadyEvent
listener.running(context);
}
}
@Override
public void running(ConfigurableApplicationContext context) {
context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
}
SpringApplication监听器
SpringApplication对象创建和run()方法的运行过程中,我们可以发现有几个重要的事件回调机制,分别是:
ApplicationContextInitializer
SpringApplicationRunListener
ApplicationRunner
CommandLineRunner
这几个重要的事件回调机制在很多环境下都有应用,例如:
启动前的环境检测
启动时的配置初始化
启动后的数据初始化