首先看一下一个SpringBoot应用的启动类:
@SpringBootApplication
public class ColdTraceWebApplication {
public static void main(String[] args) {
SpringApplication.run(ColdTraceWebApplication.class, args);
}
}
一、创建一个SpringApplication对象
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = deduceWebApplicationType();
// 利用类似java SPI机制将配置在/META-INF/spring.factories中的Initializers和Listeners实例化,并赋值给对象的属性
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
初始化过程如下:
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 利用反射创建对象
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
// 反射创建对象方法:
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
Set<String> names) {
List<T> instances = new ArrayList<>(names.size());
for (String name : names) {
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = instanceClass
.getDeclaredConstructor(parameterTypes);
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException(
"Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
二、执行run()方法
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
// SPI机制获取:所有的SpringApplicationRunListeners
SpringApplicationRunListeners listeners = getRunListeners(args);
// 事件回调:调用SpringApplicationRunListeners的starting()方法
listeners.starting();
try {
// 封装参数对象
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
// 1.准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
// 设置spring.beaninfo.ignore,默认为false,具体作用暂时还不清楚
configureIgnoreBeanInfo(environment);
// 打印banner
Banner printedBanner = printBanner(environment);
// 创建IOC容器
// 默认:AnnotationConfigApplicationContext
// web环境:AnnotationConfigServletWebServerApplicationContext
context = createApplicationContext();
// SPI机制初始化exceptionReporters
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 2.准备IOC容器
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
// 3.刷新容器
refreshContext(context);
// 容器刷新后(什么也没做)
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
// listener回调
listeners.started(context);
// 执行Runners(ApplicationRunner/CommandLineRunner)
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
// listener回调
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
下面将分析run方法执行中调用的一些重要方法:
- 准备环境
configureEnvironment()方法中继续调用configurePropertySources()和configureProfiles(). configurePropertySources方法的作用是把配置文件中的配置,和通过编码方式放入环境中的配置整合到一起private ConfigurableEnvironment prepareEnvironment( SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { // 创建environment对象 // 默认:StandardEnvironment,web环境:StandardServletEnvironment ConfigurableEnvironment environment = getOrCreateEnvironment(); // 环境的配置和配置文件 configureEnvironment(environment, applicationArguments.getSourceArgs()); // listeners事件回调(会将用户配置加载进environment) listeners.environmentPrepared(environment); // 将配置好的environment绑定给SpringApplication bindToSpringApplication(environment); if (this.webApplicationType == WebApplicationType.NONE) { environment = new EnvironmentConverter(getClassLoader()) .convertToStandardEnvironmentIfNecessary(environment); } // 将环境中的配置保存到SpringConfigurationPropertySources中 ConfigurationPropertySources.attach(environment); return environment; }
configureProfiles方法的作用是将生效的配置文件添加到环境中protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) { MutablePropertySources sources = environment.getPropertySources(); if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) { sources.addLast( new MapPropertySource("defaultProperties", this.defaultProperties)); } if (this.addCommandLineProperties && args.length > 0) { String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME; if (sources.contains(name)) { PropertySource<?> source = sources.get(name); CompositePropertySource composite = new CompositePropertySource(name); composite.addPropertySource(new SimpleCommandLinePropertySource( "springApplicationCommandLineArgs", args)); composite.addPropertySource(source); sources.replace(name, composite); } else { sources.addFirst(new SimpleCommandLinePropertySource(args)); } } }
protected void configureProfiles(ConfigurableEnvironment environment, String[] args) { environment.getActiveProfiles(); // ensure they are initialized // But these ones should go first (last wins in a property key clash) Set<String> profiles = new LinkedHashSet<>(this.additionalProfiles); profiles.addAll(Arrays.asList(environment.getActiveProfiles())); environment.setActiveProfiles(StringUtils.toStringArray(profiles)); }
-
准备IOC容器
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { // 设置环境 context.setEnvironment(environment); // 容器后置处理(根据条件设置:BeanNameGenerator,ResourceLoader,ClassLoader) postProcessApplicationContext(context); // 调用所有ApplicationContextInitializer的init()方法 applyInitializers(context); // listener回调 listeners.contextPrepared(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // Add boot specific singleton beans context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { context.getBeanFactory().registerSingleton("springBootBanner", printedBanner); } // 将所有的sources注册到容器中:这里的resource全是xxxConfiguration Set<Object> sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); load(context, sources.toArray(new Object[0])); listeners.contextLoaded(context); }
-
刷新容器,refreshContext调用著名的refresh(context)方法
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
- Listeners回调started()方法
- ApplicationRunner和CommandLineRunner的run()方法执行
- Listeners回调started()方法running()方法
- 返回IOC容器
至此,SpringBootApplication.run(Class<?> c, String args...)方法执行结束