SpringBoot启动流程解析
SpringBoot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。
下面通过源码来了解下SpringBoot的启动流程。(展示代码基于2.1.1.RELEASE)
|
|
Spring Boot的启动入口在SpringApplication.run()方法。
|
|
首先创建一个SpringApplication,然后执行run方法进行项目初始化。
初始化SpringApplication
|
|
首先根据项目中是否存在web容器相关的类来判断当前项目是否是一个web项目,然后初始化ApplicationContextInitializer和ApplicationListener,这两组类的初始化是通过SpringFactoriesLoader来进行初始化的,先看下SpringFactoriesLoader。
|
|
SpringFactoriesLoader的工作原理是在CLASSPATH下每个Jar包中的META-INF/spring.factories配置文件中找到对应类型的处理类。
在初始化SpringApplication的时候使用SpringFactoriesLoader获取所有spring.factories文件中的ApplicationContextInitializer和ApplicationListener的处理类。
ApplicationContextInitializer用于在容器refresh之前对容器进行扩展。
ApplicationListener是SpringBoot的监听器,用于监听SpringBoot应用启动过程中各个环节对应的事件(ApplicationEvent),便于开发人员在特定启动环节进行定制化扩展。
执行SpringApplication的run方法
|
|
run方法是SpringBoot整个启动过程的核心流程。
获取
SpringApplicationRunListener,SpringApplicationRunListener的默认实现是EventPublishingRunListener,其作用是用来发布SpringBoot应用启动过程中各个环节对应的事件(ApplicationEvent),由ApplicationListener来监听处理,starting方法将会发布ApplicationStartingEvent事件。创建Environment,初始化配置文件(profile)和属性文件(properties),创建完成后会发布
ApplicationEnvironmentPreparedEvent事件。输出Banner,SpringBoot启动时的面板样式。
创建Spring容器ConfigurableApplicationContext,如果是web项目则是
AnnotationConfigServletWebServerApplicationContext, 如果不是web项目则是AnnotationConfigApplicationContext。从
SpringFactoriesLoader加载SpringBootExceptionReporter用于处理启动异常,默认为FailureAnalyzers。执行
prepareContext方法,在Spring容器初始化前进行预处理。123456789101112131415161718192021222324252627private 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);}// Load the sourcesSet<Object> sources = getAllSources();Assert.notEmpty(sources, "Sources must not be empty");load(context, sources.toArray(new Object[0]));listeners.contextLoaded(context);}applyInitializer方法用于获取所有的ApplicationContextInitializer,执行其initialize方法在容器启动前进行扩展。listeners.contextPrepared(context)方法用于发布ApplicationContextInitializedEvent事件。load方法用于解析要加载的bean成为BeanDefinition注册到容器中,这里只加载了项目启动类,也就是@SpringBootApplication注解所在的bean。listeners.contextLoaded(context)方法用于发布ApplicationPreparedEvent事件。
执行
refreshContext方法,初始化Spring容器。123456789101112131415private void refreshContext(ConfigurableApplicationContext context) {refresh(context);if (this.registerShutdownHook) {try {context.registerShutdownHook();}catch (AccessControlException ex) {// Not allowed in some environments.}}}protected void refresh(ApplicationContext applicationContext) {Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);((AbstractApplicationContext) applicationContext).refresh();}该方法实际就是执行Spring容器的refresh方法进行容器的初始化,并注册了钩子用于项目关闭时,发布
ContextClosedEvent事件,然后进行容器销毁操作。下面是Spring容器的初始化流程,SpringBoot基于Spring容器进行了定制化扩展,主要通过继承
AbstractApplicationContext,以及使用Spring的扩展点BeanFactoryPostProcessor来对Spring容器进行定制扩展,下面看下主要的变化点:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263public 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();}}}obtainFreshBeanFactory()方法用于获取容器的BeanFactory,常规Spring项目的容器实现自AbstractRefreshableApplicationContext,在这一步会解析xml文件,将待加载的bean创建成BeanDefinition注册到容器中;而在SpringBoot项目中则实现自GenericApplicationContext,由于SpringBoot项目没有xml文件,所以这里没有初始化BeanDefinition,SpringBoot解析加载bean成为BeanDefinition是通过BeanFactoryPostProcessor扩展点进行的。在SpringBoot容器创建的时候,会根据是否是web项目创建AnnotationConfigServletWebServerApplicationContext或AnnotationConfigApplicationContext,这两种容器在创建时会通过AnnotationConfigUtils.registerAnnotationConfigProcessors注册一个beanName为org.springframework.context.annotation.internalConfigurationAnnotationProcessor的BeanFactoryPostProcessor,具体实现类为ConfigurationClassPostProcessor,这个类是SpringBoot初始化bean的核心类。invokeBeanFactoryPostProcessors(beanFactory)方法用于执行处理BeanFactoryPostProcessor类型扩展点,该扩展点用于在容器实例化对象之前,对注册到容器的BeanDefinition所保存的信息做一些额外的操作,比如修改bean定义的某些属性或者增加其他信息等。这里将会执行ConfigurationClassPostProcessor。1234567891011121314151617181920212223242526272829protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());... ...}final class PostProcessorRegistrationDelegate {public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {... ...List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();... ...}}这里获取的
BeanDefinitionRegistryPostProcessor实现类就是ConfigurationClassPostProcessor,执行其postProcessBeanDefinitionRegistry方法进行处理。123456789101112131415161718192021222324252627282930public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {... ...processConfigBeanDefinitions(registry);}public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {... ...// Parse each @Configuration classConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment,this.resourceLoader, this.componentScanBeanNameGenerator, registry);parser.parse(candidates);parser.validate();Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());configClasses.removeAll(alreadyParsed);// Read the model and create bean definitions based on its contentif (this.reader == null) {this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment,this.importBeanNameGenerator, parser.getImportRegistry());}this.reader.loadBeanDefinitions(configClasses);... ...}ConfigurationClassPostProcessor内部功能主要是生成ConfigurationClassParser,执行其parse方法,用来解析类上的各种注解,执行注解对应的处理逻辑,生成配置信息,最后通过reader.loadBeanDefinitions(configClasses)方法解析成BeanDefinitions,这里以SpringBoot的启动类,也就是@SpringBootApplication注解所在的类为入口进行解析。12345678910111213141516171819202122232425public void parse(Set<BeanDefinitionHolder> configCandidates) {for (BeanDefinitionHolder holder : configCandidates) {BeanDefinition bd = holder.getBeanDefinition();try {if (bd instanceof AnnotatedBeanDefinition) {parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());}else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());}else {parse(bd.getBeanClassName(), holder.getBeanName());}}catch (BeanDefinitionStoreException ex) {throw ex;}catch (Throwable ex) {throw new BeanDefinitionStoreException("Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);}}this.deferredImportSelectorHandler.process();}parse方法用于解析各种注解:@ComponentScan、@ComponentScans、@Configuration、@Component、@Bean、@Import、@ImportResource、@PropertySource。deferredImportSelectorHandler.process()方法用来处理自动配置功能。主要通过AutoConfigurationImportSelector来处理,该类是通过@SpringBootApplication注解上的@Import注解导入的,AutoConfigurationImportSelector通过SpringFactoriesLoader获取所有spring.factories文件中的EnableAutoConfiguration类型自动配置类,根据类上的@Conditional系列注解,过滤掉不需要加载的自动配置类,将剩余需要加载的自动配置类进行初始化解析。onRefresh()方法用于创建web容器,如果是web项目,则容器继承于ServletWebServerApplicationContext,将会在这一步创建web容器。123456789protected void onRefresh() {super.onRefresh();try {createWebServer();}catch (Throwable ex) {throw new ApplicationContextException("Unable to start web server", ex);}}finishRefresh()方法用于启动web容器,如果是web项目,则容器继承于ServletWebServerApplicationContext,将会在这一步启动web容器,并发布ServletWebServerInitializedEvent事件。1234567protected void finishRefresh() {super.finishRefresh();WebServer webServer = startWebServer();if (webServer != null) {publishEvent(new ServletWebServerInitializedEvent(webServer, this));}}
执行
afterRefresh来在Spring容器初始化完成后进行扩展,默认没有实现。发布
ApplicationStartedEvent事件。获取容器中的
ApplicationRunner和CommandLineRunner,执行其run方法,用于在启动完成前进行扩展。发布
ApplicationReadyEvent事件。
至此SpringBoot启动完成。从整个启动流程来看,SpringBoot的核心就是在Spring容器初始化的基础上,通过Spring的扩展点进行了定制化扩展,并进行了一层包装。主要通过继承AbstractApplicationContext,以及使用Spring的扩展点BeanFactoryPostProcessor进行扩展,并新增了ApplicationContextInitializer和ApplicationListener进行扩展。