- SpringBoot 启动方法
- 入口
- run 方法
- getRunListeners
- createSpringFactoriesInstances
- listeners.starting()
- prepareEnvironment
- configureIgnoreBeanInfo
- printBanner
- createApplicationContext
- exceptionReporters
- prepareContext
- postProcessApplicationContext
- applyInitializers
- getAllSources
- load
- listeners.contextLoaded(context)
- refreshContext
- afterRefresh
- stopWatch.stop()
- listeners.started(context)
- callRunners
- listeners.running(context)
- 入口
SpringBoot 启动方法
- Author: HuiFer
- 源码阅读仓库: SourceHot-spring-boot
入口
- 通常一个简单的 SpringBoot 基础项目我们会有如下代码
@SpringBootApplication@RestController@RequestMapping("/")public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}}
- 值得关注的有
SpringApplication.run以及注解@SpringBootApplication
run 方法
public ConfigurableApplicationContext run(String... args) {// 秒表StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationContext context = null;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();configureHeadlessProperty();// 获取监听器SpringApplicationRunListeners listeners = getRunListeners(args);// 监听器启动listeners.starting();try {// application 启动参数列表ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);// 配置忽略的bean信息configureIgnoreBeanInfo(environment);Banner printedBanner = printBanner(environment);// 创建应用上下文context = createApplicationContext();exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);// 准备上下文,装配beanprepareContext(context, environment, listeners, applicationArguments, printedBanner);// 上下文刷新refreshContext(context);// 刷新后做什么afterRefresh(context, applicationArguments);stopWatch.stop();if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}// 监听器开始了listeners.started(context);// 唤醒callRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, listeners);throw new IllegalStateException(ex);}try {// 监听器正式运行listeners.running(context);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, null);throw new IllegalStateException(ex);}return context;}
getRunListeners
- 获取监听器
private SpringApplicationRunListeners getRunListeners(String[] args) {Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };// 获取 Spring Factory 实例对象return new SpringApplicationRunListeners(logger,getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));}private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {ClassLoader classLoader = getClassLoader();// Use names and ensure unique to protect against duplicates// 读取 spring.factoriesSet<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));// 创建SpringFactory实例List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);/*** 排序 {@link Ordered}*/AnnotationAwareOrderComparator.sort(instances);return instances;}
createSpringFactoriesInstances
@SuppressWarnings("unchecked")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对象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;}
SpringFactoriesLoader.loadFactoryNames(type, classLoader)是 spring 提供的方法,主要目的是读取spring.factories文件- 读取需要创建的内容

创建完成

AnnotationAwareOrderComparator.sort(instances)排序通过 spring 的源码我们知道这个方法是根据
order的数字大小进行排序,观察SharedMetadataReaderFactoryContextInitializer
同样的再找一个
DelegatingApplicationContextInitializer
下图中的所有类都有 Order 数值返回
排序前:

排序后:

listeners.starting()
SpringApplicationRunListeners:org.springframework.boot.SpringApplicationRunListeners这个类是org.springframework.boot.SpringApplicationRunListener的集合表现形式class SpringApplicationRunListeners {private final List<SpringApplicationRunListener> listeners;SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {this.log = log;this.listeners = new ArrayList<>(listeners);}void starting() {for (SpringApplicationRunListener listener : this.listeners) {listener.starting();}}}
- 这里主要是启动
org.springframework.boot.SpringApplicationRunListener#starting方法,只有一个实现org.springframework.boot.context.event.EventPublishingRunListener#starting
prepareEnvironment
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments) {// Create and configure the environment// 得到一个环境ConfigurableEnvironment environment = getOrCreateEnvironment();// 配置环境configureEnvironment(environment, applicationArguments.getSourceArgs());ConfigurationPropertySources.attach(environment);listeners.environmentPrepared(environment);// 绑定springBoot应用bindToSpringApplication(environment);// 是否创建自定义环境if (!this.isCustomEnvironment) {environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,deduceEnvironmentClass());}ConfigurationPropertySources.attach(environment);return environment;}
configureIgnoreBeanInfo
- 获取
spring.beaninfo.ignore并且设置到环境信息中
private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {if (System.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {Boolean ignore = environment.getProperty("spring.beaninfo.ignore", Boolean.class, Boolean.TRUE);System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME, ignore.toString());}}
printBanner
private Banner printBanner(ConfigurableEnvironment environment) {if (this.bannerMode == Banner.Mode.OFF) {return null;}ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader: new DefaultResourceLoader(getClassLoader());// 创建打印器SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);if (this.bannerMode == Mode.LOG) {// 输出return bannerPrinter.print(environment, this.mainApplicationClass, logger);}// 输出return bannerPrinter.print(environment, this.mainApplicationClass, System.out);}
Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {Banner banner = getBanner(environment);banner.printBanner(environment, sourceClass, out);return new PrintedBanner(banner, sourceClass);}
最终输出内容类:
org.springframework.boot.SpringBootBannerclass SpringBootBanner implements Banner {private static final String[] BANNER = { "", " . ____ _ __ _ _"," /\\\\ / ___'_ __ _ _(_)_ __ __ _ \\ \\ \\ \\", "( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\"," \\\\/ ___)| |_)| | | | | || (_| | ) ) ) )", " ' |____| .__|_| |_|_| |_\\__, | / / / /"," =========|_|==============|___/=/_/_/_/" };private static final String SPRING_BOOT = " :: Spring Boot :: ";private static final int STRAP_LINE_SIZE = 42;@Overridepublic void printBanner(Environment environment, Class<?> sourceClass, PrintStream printStream) {for (String line : BANNER) {printStream.println(line);}String version = SpringBootVersion.getVersion();version = (version != null) ? " (v" + version + ")" : "";StringBuilder padding = new StringBuilder();while (padding.length() < STRAP_LINE_SIZE - (version.length() + SPRING_BOOT.length())) {padding.append(" ");}printStream.println(AnsiOutput.toString(AnsiColor.GREEN, SPRING_BOOT, AnsiColor.DEFAULT, padding.toString(),AnsiStyle.FAINT, version));printStream.println();}}
createApplicationContext
protected ConfigurableApplicationContext createApplicationContext() {// 获取上下文类Class<?> contextClass = this.applicationContextClass;if (contextClass == null) {try {// 根据不同类型选择创建的实例switch (this.webApplicationType) {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);}
this.applicationContextClass初始化方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));// 设置 web应用类型this.webApplicationType = WebApplicationType.deduceFromClasspath();setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));this.mainApplicationClass = deduceMainApplicationClass();}
org.springframework.boot.WebApplicationType#deduceFromClasspath
static WebApplicationType deduceFromClasspath() {if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {return WebApplicationType.REACTIVE;}for (String className : SERVLET_INDICATOR_CLASSES) {if (!ClassUtils.isPresent(className, null)) {return WebApplicationType.NONE;}}return WebApplicationType.SERVLET;}
exceptionReporters

prepareContext
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {// 上下文中设置环境context.setEnvironment(environment);// 上下文处理postProcessApplicationContext(context);// 初始化applyInitializers(context);// 监听器中放入上下文listeners.contextPrepared(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 DefaultListableBeanFactory) {((DefaultListableBeanFactory) beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}if (this.lazyInitialization) {context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());}// Load the sourcesSet<Object> sources = getAllSources();Assert.notEmpty(sources, "Sources must not be empty");// 加载上下文load(context, sources.toArray(new Object[0]));// 监听器做加载上下文操作listeners.contextLoaded(context);}
set方法就不说了
postProcessApplicationContext
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {if (this.beanNameGenerator != null) {// 注册 beanName 的生成器context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,this.beanNameGenerator);}if (this.resourceLoader != null) {if (context instanceof GenericApplicationContext) {// 设置资源加载器((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);}if (context instanceof DefaultResourceLoader) {// 设置类加载器((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());}}if (this.addConversionService) {// 转换服务context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());}}
看一下最终设置完成后的 context
context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());


applyInitializers
- 初始化应用上下文
@SuppressWarnings({ "rawtypes", "unchecked" })protected void applyInitializers(ConfigurableApplicationContext context) {for (ApplicationContextInitializer initializer : getInitializers()) {Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),ApplicationContextInitializer.class);Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");initializer.initialize(context);}}
初始化
List<ApplicationListener<?>> listeners:setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));获取
List<ApplicationListener<?>> listeners:public Set<ApplicationListener<?>> getListeners() { return asUnmodifiableOrderedSet(this.listeners);}数据结果

- 子类的具体实现不展开了
getAllSources
public Set<Object> getAllSources() {Set<Object> allSources = new LinkedHashSet<>();if (!CollectionUtils.isEmpty(this.primarySources)) {allSources.addAll(this.primarySources);}if (!CollectionUtils.isEmpty(this.sources)) {allSources.addAll(this.sources);}return Collections.unmodifiableSet(allSources);}
primarySources就是我们的项目启动类,在SpringApplication的构造器中有this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources))

load
- 加载 bean 到应用上下文
protected void load(ApplicationContext context, Object[] sources) {if (logger.isDebugEnabled()) {logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));}// bean定义加载器BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);if (this.beanNameGenerator != null) {// 设置 beanName生成器loader.setBeanNameGenerator(this.beanNameGenerator);}if (this.resourceLoader != null) {// 设置 资源加载器loader.setResourceLoader(this.resourceLoader);}if (this.environment != null) {// 设置环境loader.setEnvironment(this.environment);}// 加载loader.load();}
int load() {int count = 0;for (Object source : this.sources) {count += load(source);}return count;}
private int load(Object source) {Assert.notNull(source, "Source must not be null");if (source instanceof Class<?>) {return load((Class<?>) source);}if (source instanceof Resource) {return load((Resource) source);}if (source instanceof Package) {return load((Package) source);}if (source instanceof CharSequence) {return load((CharSequence) source);}throw new IllegalArgumentException("Invalid source type " + source.getClass());}
通过前文我们已经知道
source就是一个 class
private int load(Class<?> source) {if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {// Any GroovyLoaders added in beans{} DSL can contribute beans hereGroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);load(loader);}// 是否为组件if (isComponent(source)) {this.annotatedReader.register(source);return 1;}return 0;}
- 我们的启动类是一个组件,直接注册完成返回 1
listeners.contextLoaded(context)
- 监听器行为: 在上下文资源加载后做一些事情
refreshContext
- 上下文刷新
private void refreshContext(ConfigurableApplicationContext context) {refresh(context);if (this.registerShutdownHook) {try {context.registerShutdownHook();}catch (AccessControlException ex) {// Not allowed in some environments.}}}
/*** Refresh the underlying {@link ApplicationContext}.* @param applicationContext the application context to refresh*/protected void refresh(ApplicationContext applicationContext) {Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);((AbstractApplicationContext) applicationContext).refresh();}
- 最终来到了
org.springframework.context.support.AbstractApplicationContext#refresh方法,此方法是 spring 的一个方法,此处不在阐述
afterRefresh
刷新上下文之后做的事情,空的没有实现
protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {}
stopWatch.stop()
- 秒表结束
listeners.started(context)
- 各类监听器启动
callRunners
- 两种 runner 启动
ApplicationRunner和CommandLineRunner
private void callRunners(ApplicationContext context, ApplicationArguments args) {List<Object> runners = new ArrayList<>();runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());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);}}
listeners.running(context)
- 监听器正式开始工作
