1.从应用程序启动入口开始追踪代码:
SpringApplication.run(SpringbootDemoApplication.class, args);
2.进入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 = WebApplicationType.deduceFromClasspath();this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));this.mainApplicationClass = deduceMainApplicationClass();}
这个步骤做了以下几件事:
a.初始化资源加载器,但是从上下文可以看出是null
b.设置主资源类,即第一步传过来的SpringbootDemoApplication类
c.推断webApplicationType的类型:WebApplicationType.SERVLET
d.设置bootstrapRegistryInitializers数据,通过SpringFactoriesLoader从META-INF/spring.factories目录加载key为BootstrapRegistryInitializer的数据并初始化
e.设置initializers,通过SpringFactoriesLoader从上下文中所以jar根目录META-INF/spring.factories目录加载key为ApplicationContextInitializer的数据并初始化
f.设置listeners,通过SpringFactoriesLoader从上下文中所以jar根目录META-INF/spring.factories目录加载key为ApplicationListener的数据并初始化
j.推断主应用类,即SpringbootDemoApplication类
3.接着继续进入SpringApplication类的run方法中,如下代码:
public ConfigurableApplicationContext run(String... args) {long startTime = System.nanoTime();// a.创建一个springboot上下文对象DefaultBootstrapContext bootstrapContext = createBootstrapContext();ConfigurableApplicationContext context = null;configureHeadlessProperty();// b.获取并启动监听的listenersSpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting(bootstrapContext, this.mainApplicationClass);try {// c.初始化应用环境ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);configureIgnoreBeanInfo(environment);// 打印启动banner数据Banner printedBanner = printBanner(environment);// d.初始化应用上下文context = createApplicationContext();context.setApplicationStartup(this.applicationStartup);// e.刷新应用上下文前的准备工作prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);// f.刷新应用上下文refreshContext(context);// j.刷新应用上下文之后的扩展功能afterRefresh(context, applicationArguments);Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);}listeners.started(context, timeTakenToStartup);// h.调用ApplicationRunner和CommandLineRunner的run方法callRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, listeners);throw new IllegalStateException(ex);}try {Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);listeners.ready(context, timeTakenToReady);}catch (Throwable ex) {handleRunFailure(context, ex, null);throw new IllegalStateException(ex);}return context;}
接下来具体解释一下,每一步的细节:
a.创建springboot上下文对象:创建一个类型为DefaultBootstrapContext的上下文对象,并且将第二步获取过来的bootstrapRegistryInitializers执行初始化操作,执行initialize方法
private DefaultBootstrapContext createBootstrapContext() {DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));return bootstrapContext;}
BootstrapRegistryInitializer接口类:
@FunctionalInterface
public interface BootstrapRegistryInitializer {/*** Initialize the given {@link BootstrapRegistry} with any required registrations.* @param registry the registry to initialize*/void initialize(BootstrapRegistry registry);}
可以自行实现该接口并做某些初始化作用,这个初始化的时机比较早。
b.获取并启动监听的listeners:获取并实例化所有类型为SpringApplicationRunListener的listener
private SpringApplicationRunListeners getRunListeners(String[] args) {Class>[] types = new Class>[] { SpringApplication.class, String[].class };return new SpringApplicationRunListeners(logger,getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),this.applicationStartup);}
启动listener
void starting(ConfigurableBootstrapContext bootstrapContext, Class> mainApplicationClass) {doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),(step) -> {if (mainApplicationClass != null) {step.tag("mainApplicationClass", mainApplicationClass.getName());}});}
进入org.springframework.boot.context.event.EventPublishingRunListener#starting方法中(说明:EventPublishingRunListener这个runlistener是通过反射初始化的,通过getRunListeners反射调用的是EventPublishingRunListener(SpringApplication application, String[] args) 这个构造方法,有兴趣可以看看,里面初始化了多播器:initialMulticaster和当前应用对象:application):发布了一个ApplicationStartingEvent事件对象
@Overridepublic void starting(ConfigurableBootstrapContext bootstrapContext) {this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));}
继续追踪到org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)方法:
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));Executor executor = getTaskExecutor();for (ApplicationListener> listener : getApplicationListeners(event, type)) {if (executor != null) {executor.execute(() -> invokeListener(listener, event));}else {invokeListener(listener, event);}}}
继续追到org.springframework.context.event.SimpleApplicationEventMulticaster#doInvokeListener:
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {try {listener.onApplicationEvent(event);}catch (ClassCastException ex) {// 省略部分代码...}}
最终执行各个listener的onApplicationEvent方法。
springboot中所有的事件发布都是由org.springframework.boot.context.event.EventPublishingRunListener这个类来发布完成的,它会在容器初始化的各个阶段发布各种不同的事件,关注了这个事件的监听器就能接受到,然后执行对应的方法。
c.初始化应用环境,代码如下:
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments, Banner printedBanner) {context.setEnvironment(environment);postProcessApplicationContext(context);// 执行第二步获取的initializers方法applyInitializers(context);// 发布一个ApplicationContextInitializedEvent类型的事件,告诉listener准备监听listeners.contextPrepared(context);bootstrapContext.close(context);if (this.logStartupInfo) {logStartupInfo(context.getParent() == null);logStartupProfileInfo(context);}// Add boot specific singleton beansConfigurableListableBeanFactory beanFactory = context.getBeanFactory();beanFactory.registerSingleton("springApplicationArguments", applicationArguments);if (printedBanner != null) {beanFactory.registerSingleton("springBootBanner", printedBanner);}if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);if (beanFactory instanceof DefaultListableBeanFactory) {((DefaultListableBeanFactory) beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}}if (this.lazyInitialization) {context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());}context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));// Load the sourcesSet
d.初始化应用上下文:
context = createApplicationContext();context.setApplicationStartup(this.applicationStartup);
e.刷新应用上下文前的准备工作(跟spring无缝对接起来)org.springframework.context.support.AbstractApplicationContext#refresh:
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");// 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);StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);beanPostProcess.end();// 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) {// 省略代码...}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();contextRefresh.end();}}}
h.调用ApplicationRunner和CommandLineRunner的run方法,它的执行时机是容器启动完成的时候,实现对应的接口即可:
private void callRunners(ApplicationContext context, ApplicationArguments args) {List