日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

springboot启动流程

發布時間:2025/3/21 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 springboot启动流程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一句話總結:在context的refresh方法中,需要注冊bean definition,實例化bean.在加載bean defintion的時候使用ConfigurationClassParser類來解析我們的主類。然后在解析主類的時候發現了@EnableAutoConfiguratio注解中的@Import注解,就去處理@Import注解中的value值,然后就使用ImportSelector來獲取被配置在spring.factories中的類。這些類通常是AutoConfiguration。這些configuration中包含了各種各樣的bean

一切的開始源于AppBootstrap.main方法,它調用了SpringApplication.run(AppBootstrap.class)方法。

在SpringApplication.run(AppBootstrap.class)方法中

//SpringApplication.java public static ConfigurableApplicationContext run(Object[] sources, String[] args) {return (new SpringApplication(sources)).run(args); }

所以我們可以看到spring啟動流程大概分為兩部,new和run。所以本篇文章會從分兩個部分說明springboot的啟動流程。在訴說啟動流程的過程中,會將spring boot 的自動配置有關的東西重點拎出來。因為自動配置,我們可以什么都不做就可以啟動一個web服務,不需要在web.xml中配置servlet,也不需要在applicationcontext.xml中配置componentScan。

new SpringApplication(sources)

public SpringApplication(Object... sources) {//設置打印模式this.bannerMode = Mode.CONSOLE;this.logStartupInfo = true;this.addCommandLineProperties = true;this.headless = true;this.registerShutdownHook = true;this.additionalProfiles = new HashSet();//主要設置listeners,initializer。listeners監聽env,context的事件。initializer是在prepareContext中用來初始化contextthis.initialize(sources);}

屬性設置

headless 刑天模式?
Headless模式是在缺少顯示屏、鍵盤或者鼠標時的系統配置。?
在java.awt.toolkit和java.awt.graphicsenvironment類中有許多方法,除了對字體、圖形和打印的操作外還需要調用顯示器、鍵盤和鼠標的方法。在電腦缺少對應硬件設備的時候會拋出HeadlessException異常。但是有些類,如Canvas也可以在headless下正常使用。?
headless?
headless

初始化

initialize(sources)

private void initialize(Object[] sources) {if (sources != null && sources.length > 0) {this.sources.addAll(Arrays.asList(sources));}/*deduceWebEnvironment方法通過判斷javax.servlet.Servlet,org.springframework.web.context.ConfigurableWebApplicationContext這兩個Class是否存在判斷是否是Web環境*/this.webEnvironment = this.deduceWebEnvironment();this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));//設置mainApplicationClass為AppBootstrapthis.mainApplicationClass = this.deduceMainApplicationClass();}

ApplicationContextInitializer

在setInitializer方法中被實例化的initializer有:?

查看這些initializer的類圖:?

他們都實現了ApplicationContextInitializer。顧名思義,和上下文有關的初始化器。也就是說這些實例將在上下文初始化的時候prepareContext被使用。

public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {void initialize(C var1); }

ApplicationListener

在setListeners方法中被實例的話listener包含:?

這些listener都實現了ApplicationListener接口。這個接口表示這個接口將監聽對應的ApplicationEvent事件

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {void onApplicationEvent(E var1); }

整理幾個listener和其監聽的事件如下:

listener事件
ConfigFileApplicationListenerApplicationEnvironmentPreparedEvent,ApplicationPreparedEvent
AnsiOutputApplicationListenerApplicationEnvironmentPreparedEvent
LoggingApplicationListenerApplicationStartingEvent,ApplicationEnvironmentPreparedEvent,ApplicationPreparedEvent,ContextClosedEvent,ApplicationFailedEvent
ClasspathLoggingApplicationListenerApplicationEnvironmentPreparedEvent,ApplicationFailedEvent
BackgroundPreinitializerApplicationEnvironmentPreparedEvent
DelegatingApplicationListenerApplicationEnvironmentPreparedEvent,**
ParentContextCloserApplicationListenerParentContextAvailableEvent
ClearCachesApplicationListenerContextRefreshedEvent
FileEncodingApplicationListenerApplicationEnvironmentPreparedEvent
LiquibaseServiceLocatorApplicationListenerApplicationStartingEvent

整理這些對應關系的目的在于,在啟動流程中,會出發許多ApplicationEvent。這時會調用對應的listener的onApplicationEvent方法。?
這里是一種觀察者模式。對于觀察者模式,個人的理解為:被觀察者持有觀察者的引用,在發生某些事情的時候,調用觀察者的方法即可

setInitailizers和setListeners方法

在setInitailizers和setListeners方法中都用到了getSpringFactoriesInstances.代碼如下

private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) {return this.getSpringFactoriesInstances(type, new Class[0]);}private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {ClassLoader classLoader = Thread.currentThread().getContextClassLoader();Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);AnnotationAwareOrderComparator.sort(instances);return instances;}

在其中使用SpringFactoriesLoader來根據type,classLoader從幾個jar包之類的spring.factories中獲取類名,之后實例化對應的類。代碼如下:

public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {String factoryClassName = factoryClass.getName();try {//會查找幾個Spring的jar包中的META-INF/spring.factories文件。Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");ArrayList result = new ArrayList();while(urls.hasMoreElements()) {URL url = (URL)urls.nextElement();Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));String factoryClassNames = properties.getProperty(factoryClassName);result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));}return result;} catch (IOException var8) {throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8);}}

SpringFactoriesLoader會查找幾個Spring的jar包中的META-INF/spring.factories文件。被查找的factories文件的內容大致如下:

# PropertySource Loaders org.springframework.boot.env.PropertySourceLoader=\ org.springframework.boot.env.PropertiesPropertySourceLoader,\ org.springframework.boot.env.YamlPropertySourceLoader# Run Listeners org.springframework.boot.SpringApplicationRunListener=\ org.springframework.boot.context.event.EventPublishingRunListener# Application Context Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\ org.springframework.boot.context.ContextIdApplicationContextInitializer,\ org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\ org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer# Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.ClearCachesApplicationListener,\ org.springframework.boot.builder.ParentContextCloserApplicationListener,\ org.springframework.boot.context.FileEncodingApplicationListener,\ org.springframework.boot.context.config.AnsiOutputApplicationListener,\ org.springframework.boot.context.config.ConfigFileApplicationListener,\ org.springframework.boot.context.config.DelegatingApplicationListener,\ org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\ org.springframework.boot.logging.ClasspathLoggingApplicationListener,\ org.springframework.boot.logging.LoggingApplicationListener# Environment Post Processors org.springframework.boot.env.EnvironmentPostProcessor=\ org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\ org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor# Failure Analyzers org.springframework.boot.diagnostics.FailureAnalyzer=\ org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer# FailureAnalysisReporters org.springframework.boot.diagnostics.FailureAnalysisReporter=\ org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter

在本項目中,被查找的有:

  • spring-boot
  • spring-boot-autoconfigure
  • spring-beans
  • spring-boot-test
  • spring-boot-test-autoconfigure
  • spring-test?
    這些jar包都是被直接或者間接的被項目所依賴.

spring.factories文件的作用也就間接的實現了自動化配置。我們可以在項目下創建自己的spring.factories文件。來向spring boot啟動流程中加入我們自己需要的東西。

現在回到SetListener和setInitializer方法。他們使用SpringFactoriesLoader從spring.factories文件中獲取對應type的類名。然后實例化這些類。并將這些實例保存在springApplication的對應屬性中。?
private List<ApplicationContextInitializer<?>> initializers;?
或者private List<ApplicationListener<?>> listeners;

由于listener和initializer的構造函數幾乎為null。所以不用去關心他們在構造函數中做了什么。

run

public ConfigurableApplicationContext run(String... args) {StopWatch stopWatch = new StopWatch();stopWatch.start();//context,上下文,我們的重點對象ConfigurableApplicationContext context = null;FailureAnalyzers analyzers = null;this.configureHeadlessProperty();//new SpringApplicationRunListeners用它來統一管理listeners,在事件發生的時候調用他們SpringApplicationRunListeners listeners = this.getRunListeners(args);listeners.starting();//如果有監聽器監聽啟動事件,則執行對應的動作try {//從命令行中讀取參數作為propertySource,放入到這里,會加入到env中ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);//創建env,加載配置文件,系統的屬性,profile文件,application.yml, 初始化日志系統ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);//打印bannerBanner printedBanner = this.printBanner(environment);//創建contextcontext = this.createApplicationContext();new FailureAnalyzers(context);this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);this.refreshContext(context);this.afterRefresh(context, applicationArguments);listeners.finished(context, (Throwable)null);stopWatch.stop();if (this.logStartupInfo) {(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);}return context;} catch (Throwable var9) {this.handleRunFailure(context, listeners, (FailureAnalyzers)analyzers, var9);throw new IllegalStateException(var9);}}

獲取運行時監聽器監聽運行時發生的事件:getRunListeners

SpringApplicationRunListeners listeners = this.getRunListeners(args);

首先看SpringApplicationRunListeners類。類中包含了一個SpringApplicationRunListener的集合.

class SpringApplicationRunListeners {private final Log log;private final List<SpringApplicationRunListener> listeners; } public interface SpringApplicationRunListener {void starting();void environmentPrepared(ConfigurableEnvironment var1);void contextPrepared(ConfigurableApplicationContext var1);void contextLoaded(ConfigurableApplicationContext var1);void finished(ConfigurableApplicationContext var1, Throwable var2); }

也就是說?
在run方法中構造了一個SpringRunApplicationListeners,其中包含多個SpringRunApplicationListener,用來監聽應用啟動過程中的start,environmentPrepared,contextPrepared,contextLoaded,finished等事件。

SpringRunApplicationLinsteners中到底包含哪些RunListener呢?包含從spring.factories中實例化的。在這里,getSpringFactoroiesIntsances方法返回只包含一個實例的集合,這個實例是EventPublishingRunListener

private SpringApplicationRunListeners getRunListeners(String[] args) {Class<?>[] types = new Class[]{SpringApplication.class, String[].class};return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));}

下面看EventPublishingRunListener類。

public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {private final SpringApplication application;private final String[] args;private final SimpleApplicationEventMulticaster initialMulticaster;public EventPublishingRunListener(SpringApplication application, String[] args) {//在這里,application即SpringApplicationthis.application = application;this.args = args;this.initialMulticaster = new SimpleApplicationEventMulticaster();Iterator var3 = application.getListeners().iterator();//在SpringApplication.initailize()方法中初始化的listeners被加入到EventPublishingRunListener里面的initialMulticaster中while(var3.hasNext()) {ApplicationListener<?> listener = (ApplicationListener)var3.next();this.initialMulticaster.addApplicationListener(listener);}} }

EventPublishingRunListener通過引用SimpleApplicationEventMulticaster來完成事件的發布和ApplicationListener的管理。

接下來我們仔細看SimpleApplicationEventMulticaster這個類。?

從SimpleApplicationEventMulticaster類的結構中可以看到multicaster使用ListenerRetriever來管理ApplicationListener。使用了retrieverCache:ConcurrentHashMap

廣播ApplicationStartedEvent事件:listeners.starting()

在上一步使用SpringRunApplicationListeners將所有的listener管理起來后,開始傳播start事件

//EventPublishingRunListenerpublic void starting() {this.initialMulticaster.multicastEvent(new ApplicationStartedEvent(this.application, this.args));}

需要注意的是:

public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);//在這一步getApplicationListeners(event,type)中,會從所有的listener中取出支持這個事件類型的listener,一個新的retriever會持有這些listener的引用作為value,另外以(event,source)作為key,存在retrieverCache中。Iterator var4 = this.getApplicationListeners(event, type).iterator();while(var4.hasNext()) {final ApplicationListener<?> listener = (ApplicationListener)var4.next();Executor executor = this.getTaskExecutor();if (executor != null) {executor.execute(new Runnable() {public void run() {SimpleApplicationEventMulticaster.this.invokeListener(listener, event);}});} else {this.invokeListener(listener, event);}}}

在listener.starting()這一部中,幾個listener都沒有做什么動作。

構造應用參數:new DefaultApplicationArguments(args)

創建DefaultApplicationArguments的作用是將參數存儲在DefaultApplicationArguments的內部類Source中。?
其中Source的類結構如圖:?

我們追尋Source的構造函數可以發現,使用SimpleCommandLineArgsParser來解析參數,將解析后的參數存到PropertySource的source屬性中。?
這里由于沒有什么參數,所以略過。

創建和準備環境:environment

ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {//創建env,如果是web環境,則創建StandardServletEnvironment,如果不是StandardEnvironmentConfigurableEnvironment environment = this.getOrCreateEnvironment();//配置envthis.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());//廣播environment事件listeners.environmentPrepared((ConfigurableEnvironment)environment);if (!this.webEnvironment) {environment = (new EnvironmentConverter(this.getClassLoader())).convertToStandardEnvironmentIfNecessary((ConfigurableEnvironment)environment);}return (ConfigurableEnvironment)environment;}

這段代碼主要分為幾個步驟:?
1. 創建Env?
2. 配置Env?
3. 調用監聽器廣播ApplicationEnvironmentPreparedEvent事件

創建Env

private ConfigurableEnvironment getOrCreateEnvironment() {if (this.environment != null) {return this.environment;} else {return (ConfigurableEnvironment)(this.webEnvironment ? new StandardServletEnvironment() : new StandardEnvironment());}}

如果是Web環境,則創建StandardServletEnvironment,否則創建StandardEnvironment.?
下面的代碼是有關Environment和ConfigurableEnvironment接口.?
我們可以從接口中看出Environment主要作用為:獲取系統的環境和spring的profile文件中的內容,存儲到PropertySource中。

public interface Environment extends PropertyResolver {String[] getActiveProfiles();String[] getDefaultProfiles();boolean acceptsProfiles(String... var1); } public interface ConfigurableEnvironment extends Environment, ConfigurablePropertyResolver {void setActiveProfiles(String... var1);void addActiveProfile(String var1);void setDefaultProfiles(String... var1);MutablePropertySources getPropertySources();Map<String, Object> getSystemEnvironment();Map<String, Object> getSystemProperties();void merge(ConfigurableEnvironment var1); }

有關Env的類圖:?

在environment初始化之后,PropertySources中包含的幾個PropertySource為4個:?
1. servletContextInitParam?
2. servletConfigInitParams?
3. systemEnv?
4. systemProperties

簡單說下PropertySource的結構

//代表了name/value屬性對的資源。source可以任何一種封裝了屬性值得類型??梢允荘roperties,Map,ServletContext,ServletConfig //一般都很少單獨使用PropertySource,而是使用PropertySources public abstract class PropertySource<T> {protected final Log logger;protected final String name;protected final T source; } //PropertySources中聚合了多個PropertySource,包含PropertyResolver的實現可以實現從PropertySource中搜索 public interface PropertySources extends Iterable<PropertySource<?>> {boolean contains(String var1);PropertySource<?> get(String var1); }

當和@Configuration一起工作時,@PropertySource注解可以方便得為當前環境加入配置文件?
和PropertySource相關的類圖:?

配置env

protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {this.configurePropertySources(environment, args);this.configureProfiles(environment, args);}//這兩個函數分別用來添加命令行參數的PropertySource和設置activeProfile。由于項目中沒有這些則略過

廣播ApplicationEnvironmentPreparedEvent事件

調用RunListener,廣播ApplicationEnvironmentPreparedEvent事件。受到影響的listener列在下表

listener事件
ConfigFileApplicationListenerApplicationEnvironmentPreparedEvent,ApplicationPreparedEvent
AnsiOutputApplicationListenerApplicationEnvironmentPreparedEvent
LoggingApplicationListenerApplicationStartingEvent,ApplicationEnvironmentPreparedEvent,ApplicationPreparedEvent,ContextClosedEvent,ApplicationFailedEvent
ClasspathLoggingApplicationListenerApplicationEnvironmentPreparedEvent,ApplicationFailedEvent
BackgroundPreinitializerApplicationEnvironmentPreparedEvent
DelegatingApplicationListenerApplicationEnvironmentPreparedEvent,**
FileEncodingApplicationListenerApplicationEnvironmentPreparedEvent

加載配置文件:ConfigFileApplicationListener。注意application.proporties文件在這一步加載

private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {//ConfigFileApplicationListener使用EnvironmentPostProcessor來處理environmentList<EnvironmentPostProcessor> postProcessors = this.loadPostProcessors();postProcessors.add(this);AnnotationAwareOrderComparator.sort(postProcessors);Iterator var3 = postProcessors.iterator();while(var3.hasNext()) {EnvironmentPostProcessor postProcessor = (EnvironmentPostProcessor)var3.next();postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());}}

EnvironmentPostProcessor會在應用上下文刷新之前定制應用的環境。EnvironmentPostProcessor的實現類需要注冊在META-INF/spring.factories文件中,并且用類的全路徑名作為key。并且其實現類被鼓勵實現Ordered接口或者@Order注解,Ordered接口和@Order的作用在于將容器內的bean排序。?
EnvironmentPostProcessor從中所周知的路徑中加載屬性文件用來配置應用上下文的環境。默認情況是:從classpath:,file:./,classpath:config/,file:./config/:四個位置加載applicatin.properties或者application.yml。?
我們可以將EnvironmentPostProcessor作為一個動態管理配置文件的接口。?
EnvironmentPostProcessor的擴展

回到ConfigFileApplicationListener的onApplicationEnvironmentPreparedEvent方法,它獲取所有的EnvironmentPostProcessor來postProcessEnvironment。

1. SpringApplicationJsonEnvironmentPostProcessor?
? ? 從Env中現有的配置解析spring.application.json.如果有值,則向env中添加一個MapPropertySource。spring.applictaion.json的值可以通過命令行參數傳遞進來
2. CloudFoundryVcapEnvironmentPostProcessor?
? ? 從已經存在的env中尋找到VCAP
3. ConfigFileApplicationListener?
? 從配置路徑中加載application.properties/yml/xml

Spring Boot允許針對不同的環境配置不同的配置參數,可以使用 properties文件、YAML 文件、環境變量或者命令行參數來修改應用的配置。你可以在代碼中使用@Value注解來獲取配置參數的值

經過這一步加載過后env中包含的ProperytySource有:

  • 命令行參數
  • 來自SPRING_APPLICATION_JSON的屬性
  • java:comp/env 中的 JNDI 屬性
  • Java系統環境變量
  • 操作系統環境變量
  • RandomValuePropertySource,隨機值,使用 random.* 來定義
  • jar包外的 Profile 配置文件,如 application-{profile}.properties 和 YAML 文件
  • jar包內的Profile 配置文件,如 application-{profile}.properties 和 YAML 文件
  • jar包外的Application 配置,如 application.properties 和 application.yml
  • 文件jar 包內的Application 配置,如 application.properties 和application.yml 文件
  • 在標有@Configuration 注解的類標有@PropertySource注解的
  • 默認值,使用SpringApplication.setDefaultProperties 設置的
  • 設置輸出格式AnsiOutputApplicationListener

    AnsiOutputApplicationListener 根據spring.output.ansi.enabled的值來配置AnsiOutput

    完成日志系統的集成:LoggingApplicationListener

    SpringBoot在這一步完成與日志系統的集成。項目中如果使用了spring boot starter則默認使用logback。我們可以使用自己需要用的日志。只需要將適當的庫添加到classpath,便激活各種日志系統。在classpath根目錄可以提供一個合適命名的配置文件來定制日志系統。我們不需要在application.properties中做額外的操作。?
    spring的日志管理,寫的很贊的一篇?
    在ApplicationStartedEvent事件中,LoggingApplicationListener尋找合適的日志系統?
    在ApplicationEnvironmentPrepared事件中,LoggingApplicationListener尋找到配置文件并且初始化日志系統

    加快應用初始化BackgroundPreinitializer

    spring boot 為了加速應用的初始化,在后臺線程提前初始化一些耗時的任務

    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {try {Thread thread = new Thread(new Runnable() {public void run() {this.runSafely(new BackgroundPreinitializer.MessageConverterInitializer(null));this.runSafely(new BackgroundPreinitializer.MBeanFactoryInitializer(null));this.runSafely(new BackgroundPreinitializer.ValidationInitializer(null));this.runSafely(new BackgroundPreinitializer.JacksonInitializer(null));this.runSafely(new BackgroundPreinitializer.ConversionServiceInitializer(null));}public void runSafely(Runnable runnable) {try {runnable.run();} catch (Throwable var3) {;}}}, "background-preinit");thread.start();} catch (Exception var3) {;}}

    創建和準備環境這一步做的事情總結如下:?
    1. 加載配置文件?
    2. 初始化日志系統?
    3. 提前加載某些后臺的進程。在這些進程中創建一些消息轉換器等

    打印Banner


    Banners:持有多個Bannner,循環打印?
    PrintBanner:持有一個Banner,打印?
    Banner可以打印在Console,也可以打印到日志文件中。所以有不同的輸出路徑。print函數應該有一個參數為OutputStream,用來做不同的輸出方式?
    感興趣的是使用?
    AnsiOutput.toString(new Object[]{AnsiColor.GREEN, ” :: Spring Boot :: “, AnsiColor.DEFAULT, padding, AnsiStyle.FAINT, version})方法輸出有顏色的

    創建應用上下文 createApplicationContext

    protected ConfigurableApplicationContext createApplicationContext() {Class<?> contextClass = this.applicationContextClass;if (contextClass == null) {try {contextClass = Class.forName(this.webEnvironment ? "org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext" : "org.springframework.context.annotation.AnnotationConfigApplicationContext");} catch (ClassNotFoundException var3) {throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);}}return (ConfigurableApplicationContext)BeanUtils.instantiate(contextClass);}

    如果當前是Web應用,則實例化AnnotationConfigEmbeddedWebApplicationContext,否則實例化AnnotationConfigApplicationContext;?
    想要了解ApplicationContext的實例化過程中都做了什么,必須了解其類結構。

    ApplicationContext有關的類結構

    作為一個Context,ApplicationContext被賦予了很多功能。
    ? ? EnvironmentCapable,攜帶環境的
    ? ? ApplicationEventPublisher:發布事件
    ? ? SingletonBeanRegistry:注冊單例bean
    ? ? ListableBeanFactory:bean工廠
    ? ? DefaultResourceLoader:加載資源
    ? ? BeanDefinitionRegistry:注冊bean定義

    我們追尋其構造方法,發現分別在AbstractApplicationContext和GenericApplicationContext和AnnotationConfigEmbeddedWebApplicationContext三個類中有構造方法。?
    AbstractApplicationContext

    1. 設置Log
    2. 設置id和displayName
    3. **初始化BeanFactoryPostProcessor的集合**
    4. active,closed初始化
    5. 初始化ApplicationListener的集合
    6. 設置resourcePatternResolver

    2. GenericApplicationContext

    1. customClassLoader = false
    2. refreshed = false
    3. **beanFactory = new DefaultListableBeanFactory**

    3. AnnotationConfigEmbeddedWebApplicationContext

    1. **this.reader = new AnnotatedBeanDefinitionReader(this);**
    2. **this.scanner = new ClassPathBeanDefinitionScanner(this);**

    我們簡單介紹context中幾個比較重要的類

    BeanFactoryPostProcessor,DefaultListableBeanFactory,?
    AnnotatedBeanDefinitionReader,ClassPathBeanDefinitionScanner;

    BeanFactoryPostProcessor

    可以修改應用上下文的bean definition,以適應上下文底層bean工廠的屬性?
    spring boot會給我們提供一些默認的PostProcessor

    DefaultListableBeanFactory

    BeanFactory

    Bean容器的根接口。這個接口需要被含有許多bean definition(每一個bean definition有一個唯一的String名字來標識)的對象所實現。根據bean definition,bean容器會返回一個獨立的實例或者一個共享的單例。具體返回哪種,需要根據bean 容器的配置。這里說的類型就是Scope?
    BeanFactory是應用組件的集中注冊器。我們在使用中最好使用DI(push推配置)來通過構造器或者settter方法來配置對象。而不是使用任何的pull配置來配置對象,比如通過一個BeanFactory查找。Spring的DI是被BeanFactory及其子類來實現的。?
    和ListableBeanFactory相反的是,HierarachalBeanFactory會在查找parent factory。如果一個bean沒有查找到,會查找parent factory。子層次中的beans可以覆蓋父層次中的相同名字的bean.

    Bean Factory的實現需要支持標準的bean 的生命周期。下面是全部的初始化方法和他們的排序。?
    BeanNameAware’s setBeanName?
    BeanClassLoaderAware’s setBeanClassLoader?
    BeanFactoryAware’s setBeanFactory?
    EnvironmentAware’s setEnvironment?
    EmbeddedValueResolverAware’s setEmbeddedValueResolver?
    ResourceLoaderAware’s setResourceLoader (only applicable when running in an application context)?
    ApplicationEventPublisherAware’s setApplicationEventPublisher (only applicable when running in an application context)?
    MessageSourceAware’s setMessageSource (only applicable when running in an application context)?
    ApplicationContextAware’s setApplicationContext (only applicable when running in an application context)?
    ServletContextAware’s setServletContext (only applicable when running in a web application context)?
    postProcessBeforeInitialization methods of BeanPostProcessors?
    InitializingBean’s afterPropertiesSet?
    a custom init-method definition?
    postProcessAfterInitialization methods of BeanPostProcessors?
    在一個bean fatcory被關閉的時候,需要執行的生命周期的方法是:

    postProcessBeforeDestruction methods of DestructionAwareBeanPostProcessors?
    DisposableBean’s destroy?
    a custom destroy-method definitions.?
    BeanDefinitionRegistry?
    注冊bean definition的接口。通常有BeanFactories來實現。Spring 的bean definition Reader需要使用這個接口。眾所周知的實現是DefaultListableBeanFactory 和GenericApplicationContext.

    DefaultListableBeanFactory?
    ListableBeanFactory和BeanDefinitionRegistry的實現。基于bean definition的bean factory.典型的用法是在獲取bean之前,注冊所有的bean definition。因此 bean definition的查找實在本地的集合中通過預先構建的bean definition metedata進行,是一項輕松的操作。?
    可以被作為一個標準的bean factory,或者是一個自定義工廠的父類。特定類型的bean definition 格式的讀取器是獨立實現的,而不是作為bean factory的子類。比如 PropertiesBeanDefinitionReader和XmlBeanDefinitionReader

    AnnotatedBeanDefinitionReader

    顧名思義:讀取注解的bean definition的定義。?
    在GenericWebApplicationContext中構造了它的一個實例??匆幌滤臉嬙旌瘮?。

    public class AnnotatedBeanDefinitionReader {private final BeanDefinitionRegistry registry;//context本身private BeanNameGenerator beanNameGenerator;private ScopeMetadataResolver scopeMetadataResolver;private ConditionEvaluator conditionEvaluator;public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {this(registry, getOrCreateEnvironment(registry));}public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {//bean的名字生成器this.beanNameGenerator = new AnnotationBeanNameGenerator();//用來解析scope元數據this.scopeMetadataResolver = new AnnotationScopeMetadataResolver();Assert.notNull(registry, "BeanDefinitionRegistry must not be null");Assert.notNull(environment, "Environment must not be null");this.registry = registry;//bean定義注冊器,用來容納bean definitionthis.conditionEvaluator = new ConditionEvaluator(registry, environment, (ResourceLoader)null);//用來判斷是否需要跳過注解//我們需要關注這一步。原因是它注冊了一個 ConfigurationClassPostProcessor AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);} }

    我們可以看到AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);這個方法里面做了這幾件事情:?
    1. 設置beanfactory的依賴比較器?
    2. 設置beanfactory的autowire候選解析器?
    3. 給beanfatory注冊幾個postprocessor的bean definition。

    這幾個PostProcessor中含有一個特別重要的ConfigurationClassPostProcessor。就是這個類使用ConfigurationClassParser完成了basepackage目錄下的bean的掃描,并循環處理這些類(處理其中的內部類,methodbean,import,接口,importResource,ProportyResource類)。

    //AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {registerAnnotationConfigProcessors(registry, (Object)null);}public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, Object source) {DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);...Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet(4);RootBeanDefinition def;if (!registry.containsBeanDefinition("org.springframework.context.annotation.internalConfigurationAnnotationProcessor")) {//這里這里這里def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalConfigurationAnnotationProcessor"));}....return beanDefs;}private static BeanDefinitionHolder registerPostProcessor(BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {definition.setRole(2);registry.registerBeanDefinition(beanName, definition);return new BeanDefinitionHolder(definition, beanName);}

    ClassPathBeanDefinitionScanner

    同樣,一個好的名字能夠讓人理解這個類的功能。?
    ClassPathBeanDefinitionScanner是一個bean definition的掃描器,可以掃描類路徑下的候選的bean,并在給定的registry注冊bean definition。?
    需要配置類型過濾器來發現候選bean。默認的filters包含@Component,@Repository,@Service,@Controller注解。同樣支持Java EE 6’s的ManagedBean和JSR-330’s Named 的注解

    public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {this(registry, true);}public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {this(registry, useDefaultFilters, getOrCreateEnvironment(registry));}public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment) {this(registry, useDefaultFilters, environment, registry instanceof ResourceLoader ? (ResourceLoader)registry : null);}public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment, ResourceLoader resourceLoader) {this.beanDefinitionDefaults = new BeanDefinitionDefaults();//beanName生成器this.beanNameGenerator = new AnnotationBeanNameGenerator();//scope元數據解析器this.scopeMetadataResolver = new AnnotationScopeMetadataResolver();this.includeAnnotationConfig = true;Assert.notNull(registry, "BeanDefinitionRegistry must not be null");this.registry = registry;//是否使用默認的類型過濾器。如果是,則注冊默認的類型過濾器。if (useDefaultFilters) {this.registerDefaultFilters();}this.setEnvironment(environment);this.setResourceLoader(resourceLoader);}protected void registerDefaultFilters() {this.includeFilters.add(new AnnotationTypeFilter(Component.class));ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();try {this.includeFilters.add(new AnnotationTypeFilter(ClassUtils.forName("javax.annotation.ManagedBean", cl), false));this.logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");} catch (ClassNotFoundException var4) {;}try {this.includeFilters.add(new AnnotationTypeFilter(ClassUtils.forName("javax.inject.Named", cl), false));this.logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");} catch (ClassNotFoundException var3) {;}}

    我們可以在BeanDefinitionDefaults發現一些東西。

    public class BeanDefinitionDefaults {private boolean lazyInit;private int dependencyCheck = 0;private int autowireMode = 0;private String initMethodName;private String destroyMethodName; }

    初始化過程

    至此,context的初始化過程完畢。我們回顧一下context在構造函數中做了什么?
    AbstractApplicationContext?
    1. 設置Log?
    2. 設置id和displayName?
    3.?初始化BeanFactoryPostProcessor的集合?
    4. active,closed初始化?
    5. 初始化ApplicationListener的集合?
    6. 設置resourcePatternResolver?
    GenericApplicationContext?
    1. customClassLoader = false?
    2. refreshed = false?
    3.?beanFactory = new DefaultListableBeanFactory?
    AnnotationConfigEmbeddedWebApplicationContext?
    1.?this.reader = new AnnotatedBeanDefinitionReader(this);注冊了幾個BeanDefinition,最重要的是CongiurationClassPostProcessor的bean definition?
    2.?this.scanner = new ClassPathBeanDefinitionScanner(this);設置了需要識別的注解的類型

    失敗分析器

    準備上下文prepareContext

    我們初始化之后的ApplicationContext是最原始的狀態。需要配置之前創建好的Environment,SpringApplicationRunListeners,ApplicationArguments,Banner

    private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {context.setEnvironment(environment);//設置envthis.postProcessApplicationContext(context);//如果SpringApplication類的beanNameGenerator,resourceLoader不為null,則設置到context中去。//使用initializer做些初始化的動作//1. 調用用戶配置的initializer的方法//2. 設置context的Id//3. context注冊 ConfigurationWarningsPostProcessor用于檢查錯誤的配置//4. 向env中設置實際的端口//5. SharedMetadataReaderFactoryContextInitializer.CachingMetadataReaderFactoryPostProcessor//6. 設置ContextRefreshedEvent監聽器,打印ConditionEvaluationReport日志this.applyInitializers(context);listeners.contextPrepared(context);if (this.logStartupInfo) {this.logStartupInfo(context.getParent() == null);this.logStartupProfileInfo(context);}context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments);if (printedBanner != null) {context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);}Set<Object> sources = this.getSources();Assert.notEmpty(sources, "Sources must not be empty");this.load(context, sources.toArray(new Object[sources.size()]));listeners.contextLoaded(context);}

    使用initializer初始化context

    protected void applyInitializers(ConfigurableApplicationContext context) {Iterator var2 = this.getInitializers().iterator();while(var2.hasNext()) {ApplicationContextInitializer initializer = (ApplicationContextInitializer)var2.next();//獲取initailizer的類型參數的類型Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ApplicationContextInitializer.class);Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");//使用initializer來初始化contextinitializer.initialize(context);}} initializer用途
    DelegatingApplicationContextInitializer從context中獲取env,從中獲取用戶是否配置了context.initializer.classes類。如果配置了這些類,則初始化他們并調用對應的initialize方法
    ContextIdApplicationContextInitializer從env中解析名字和端口號,最后兩者組合,設置為applicationContext的Id.我們在context的構造函數中給context設置的id值是context.toString即org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@2b43529a。這一步之后,Id值為application:9188
    ConfigurationWarningsApplicationContextInitializer這個初始化器的作用在于向context中注冊ConfigurationWarningsPostProcessor,用于檢查錯誤的配置和報告錯誤
    ServerPortInfoApplicationContextInitializerApplicationContextInitializer向env設置EmbeddedServletContainer服務器實際監聽的端口。實現這個功能的方法是:向context添加一個ApplicationListener,監聽EmbeddedServletContainerInitializedEvent事件。當事件到達時,設置env中的local.server.port為實際端口值
    SharedMetadataReaderFactoryContextInitializer?
    AutoConfigurationReportLoggingInitializer向applicationContext添加ApplicationListener用來監聽ContextRefreshedEvent或者ApplicationFailedEvent事件。當事件發生時,打印ConditionEvaluationReport日志到info級別,如果出錯,則打印到debug級別

    總的來說:applyInitializers的所作的事情:?
    1. 調用用戶配置的initializer的方法?
    2. 設置context的Id?
    3. context注冊 ConfigurationWarningsPostProcessor用于檢查錯誤的配置?
    4. 向env中設置實際的端口?
    5. SharedMetadataReaderFactoryContextInitializer.CachingMetadataReaderFactoryPostProcessor?
    6. 設置ContextRefreshedEvent監聽器,打印ConditionEvaluationReport日志

    向listeners廣播contextPrepared

    EventPublishingSpringApplicationRunListener中什么都沒有做

    打印啟動日志

    if (this.logStartupInfo) {//使用StartupInfoLogger打印啟動信息.StartUpInfoLogger可以打印應用的starting,started的信息this.logStartupInfo(context.getParent() == null);this.logStartupProfileInfo(context);}protected void logStartupProfileInfo(ConfigurableApplicationContext context) {Log log = this.getApplicationLog();if (log.isInfoEnabled()) {String[] activeProfiles = context.getEnvironment().getActiveProfiles();if (ObjectUtils.isEmpty(activeProfiles)) {String[] defaultProfiles = context.getEnvironment().getDefaultProfiles();log.info("No active profile set, falling back to default profiles: " + StringUtils.arrayToCommaDelimitedString(defaultProfiles));} else {log.info("The following profiles are active: " + StringUtils.arrayToCommaDelimitedString(activeProfiles));}}}

    打印結果為

    INFO [11:57:12.206][main][org.springframework.boot.StartupInfoLogger][48]:Starting AppBootstrap on candydeMacBook-Pro.local with PID 19129 (/Users/maoyanyule/IdeaProjects/movie-pressurer/provider/target/classes started by maoyanyule in /Users/maoyanyule/IdeaProjects/movie-pressurer) INFO [11:58:25.218][main][org.springframework.boot.SpringApplication][593]:No active profile set, falling back to default profiles: default

    注冊兩個兩個單例bean

    context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments);if (printedBanner != null) {context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);}

    此時context.singletonObject中有三個對象:?
    1. springApplicationArguments?
    2. springBootBanner?
    3. autoConfigurationReport

    將source加載到context中

    protected void load(ApplicationContext context, Object[] sources) {if (logger.isDebugEnabled()) {logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));}BeanDefinitionLoader loader = this.createBeanDefinitionLoader(this.getBeanDefinitionRegistry(context), sources);if (this.beanNameGenerator != null) {loader.setBeanNameGenerator(this.beanNameGenerator);}if (this.resourceLoader != null) {loader.setResourceLoader(this.resourceLoader);}if (this.environment != null) {loader.setEnvironment(this.environment);}loader.load();}

    創建BeanDefinitionLoader,加載bean definition

    創建bean definition Loader

    BeanDefinitionLoaderbean 定義加載器??紤]bean definition的幾種方式。有注解和Xml類型,同時需要掃描主類所在的目錄。所以應該有AnnotatedBeanDefinitionReader,XmlBeanDefinitionReader

    BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {Assert.notNull(registry, "Registry must not be null");Assert.notEmpty(sources, "Sources must not be empty");this.sources = sources;this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);this.xmlReader = new XmlBeanDefinitionReader(registry);if (this.isGroovyPresent()) {this.groovyReader = new GroovyBeanDefinitionReader(registry);}this.scanner = new ClassPathBeanDefinitionScanner(registry);this.scanner.addExcludeFilter(new BeanDefinitionLoader.ClassExcludeFilter(sources));}

    AnnotatedBeanDefinitionReader,ClassPathBeanDefinitionScanner在前文已經解釋過?
    XmlBeanDefinitionReader?加載XML文件,并委托BeanDefinitionDocumentReader讀取Xml文件,BeanDefinitionDocumentReader會在給定的bean fatcory注冊bean definition。

    加載bean definition

    調用BeanDefinitionLoader.load()方法

    //循環加載所有的sources public int load() {int count = 0;Object[] var2 = this.sources;//這里的sources只有主類一個int var3 = var2.length;for(int var4 = 0; var4 < var3; ++var4) {Object source = var2[var4];count += this.load(source);}return count;}//根據不同的source類型使用不同的方法加載private int load(Object source) {Assert.notNull(source, "Source must not be null");if (source instanceof Class) {return this.load((Class)source);} else if (source instanceof Resource) {return this.load((Resource)source);} else if (source instanceof Package) {return this.load((Package)source);} else if (source instanceof CharSequence) {return this.load((CharSequence)source);} else {throw new IllegalArgumentException("Invalid source type " + source.getClass());}}//因為source為主類,所以是這個方法private int load(Class<?> source) {if (this.isGroovyPresent() && BeanDefinitionLoader.GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {BeanDefinitionLoader.GroovyBeanDefinitionSource loader = (BeanDefinitionLoader.GroovyBeanDefinitionSource)BeanUtils.instantiateClass(source, BeanDefinitionLoader.GroovyBeanDefinitionSource.class);this.load(loader);}//如果source被component注解,則使用AnnotatedBeanDefinitionReader來注冊source的bean definitionif (this.isComponent(source)) {this.annotatedReader.register(new Class[]{source});return 1;} else {return 0;}}

    我們來看AnnotatedBeanDefinitionReader是如何注冊一個source 的bean definition的

    public void register(Class... annotatedClasses) {Class[] var2 = annotatedClasses;int var3 = annotatedClasses.length;for(int var4 = 0; var4 < var3; ++var4) {Class<?> annotatedClass = var2[var4];this.registerBean(annotatedClass);}}public void registerBean(Class<?> annotatedClass) {this.registerBean(annotatedClass, (String)null, (Class[])null);}public void registerBean(Class<?> annotatedClass, Class... qualifiers) {this.registerBean(annotatedClass, (String)null, qualifiers);}//主要是在這里public void registerBean(Class<?> annotatedClass, String name, Class... qualifiers) {//獲取一個Class的bean定義,初始獲取的bean definition。AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);//判斷是否應該跳過這次注冊if (!this.conditionEvaluator.shouldSkip(abd.getMetadata())) {//從source的注解中獲取作用域,并設置到bean definition中ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);abd.setScope(scopeMetadata.getScopeName());//獲取bean的名字String beanName = name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry);//處理bean definition中的一些屬性AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);if (qualifiers != null) {Class[] var7 = qualifiers;int var8 = qualifiers.length;for(int var9 = 0; var9 < var8; ++var9) {Class<? extends Annotation> qualifier = var7[var9];if (Primary.class == qualifier) {abd.setPrimary(true);} else if (Lazy.class == qualifier) {abd.setLazyInit(true);} else {abd.addQualifier(new AutowireCandidateQualifier(qualifier));}}}//BeanDefinitionHolder中含有beanName,bean definitionBeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);//將作用域作用在bean definition 上definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);//在context中注冊bean definition BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);}}

    在這里涉及到了 bean definition 的注冊。?
    BeanDefinition的類圖?

    我們從AbstaractBeanDefinition可以看出一些眼熟的東西:

    public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor implements BeanDefinition, Cloneable {public static final String SCOPE_DEFAULT = "";//autowire類型,和AutowireCapableBeanFactory是對應的public static final int AUTOWIRE_NO = 0;public static final int AUTOWIRE_BY_NAME = 1;public static final int AUTOWIRE_BY_TYPE = 2;public static final int AUTOWIRE_CONSTRUCTOR = 3;/** @deprecated */@Deprecatedpublic static final int AUTOWIRE_AUTODETECT = 4;//dependency_check類型public static final int DEPENDENCY_CHECK_NONE = 0;public static final int DEPENDENCY_CHECK_OBJECTS = 1;public static final int DEPENDENCY_CHECK_SIMPLE = 2;public static final int DEPENDENCY_CHECK_ALL = 3;public static final String INFER_METHOD = "(inferred)";//bean classprivate volatile Object beanClass;private String scope;private boolean abstractFlag;private boolean lazyInit;private int autowireMode;private int dependencyCheck;private String[] dependsOn;private boolean autowireCandidate;private boolean primary;private final Map<String, AutowireCandidateQualifier> qualifiers;private boolean nonPublicAccessAllowed;private boolean lenientConstructorResolution;private String factoryBeanName;private String factoryMethodName;private ConstructorArgumentValues constructorArgumentValues;private MutablePropertyValues propertyValues;private MethodOverrides methodOverrides;private String initMethodName;private String destroyMethodName;private boolean enforceInitMethod;private boolean enforceDestroyMethod;private boolean synthetic;private int role;private String description;private Resource resource; }

    在這一步完成之后,context中包含了一個和主類有關的bean definition.

    廣播contextLoaded事件

    public void contextLoaded(ConfigurableApplicationContext context) {ApplicationListener listener;//在spring boot initializ()方法中初始化的listeners直到這一步才被添加到context的listener中for(Iterator var2 = this.application.getListeners().iterator(); var2.hasNext(); context.addApplicationListener(listener)) {listener = (ApplicationListener)var2.next();//如果listener中需要context實例,則設置if (listener instanceof ApplicationContextAware) {((ApplicationContextAware)listener).setApplicationContext(context);}}//廣播ApplicationPreparedEvent事件this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));} listener事件
    ConfigFileApplicationListenerApplicationEnvironmentPreparedEvent,ApplicationPreparedEvent
    LoggingApplicationListenerApplicationStartingEvent,ApplicationEnvironmentPreparedEvent,ApplicationPreparedEvent,ContextClosedEvent,ApplicationFailedEvent
    DelegatingApplicationListenerApplicationEnvironmentPreparedEvent,**

    我們有三個listener關心ApplicationPreparedEvent事件?
    ConfigFileApplicationListener?
    向context中添加ConfigFileApplicationListener.PropertySourceOrderingPostProcessor?
    LoggingApplicationListener?
    向context中注冊單例bean:springBootLoggingSystem?
    DelegatingApplicationListener繼續想其他listeners廣播事件

    prepareContext回顧

  • 調用用戶配置的initializer的方法
  • 設置context的Id
  • context注冊 ConfigurationWarningsPostProcessor用于檢查錯誤的配置
  • 向env中設置實際的端口
  • SharedMetadataReaderFactoryContextInitializer.CachingMetadataReaderFactoryPostProcessor
  • 設置ContextRefreshedEvent監聽器,打印ConditionEvaluationReport日志
  • 打印啟動日志
  • 注冊固定的單例bean
  • 加載主類的bean definition
  • 向context中添加ConfigFileApplicationListener.PropertySourceOrderingPostProcessor
  • 刷新context refreshContext

    private void refreshContext(ConfigurableApplicationContext context) {this.refresh(context);if (this.registerShutdownHook) {try {context.registerShutdownHook();} catch (AccessControlException var3) {;}}}protected void refresh(ApplicationContext applicationContext) {Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);//最終調用了applicationContext的refresh()函數((AbstractApplicationContext)applicationContext).refresh();}

    而查看applicationContext.refresh()方法時需要注意其繼承結構。附上applicationContext的類圖?

    //EmbeddedWebApplicationContext.java public final void refresh() throws BeansException, IllegalStateException {try {super.refresh();//調用的是AbstractApplicationContext} catch (RuntimeException var2) {this.stopAndReleaseEmbeddedServletContainer();throw var2;}} //AbstractApplicationContext.java public void refresh() throws BeansException, IllegalStateException {Object var1 = this.startupShutdownMonitor;synchronized(this.startupShutdownMonitor) {//1. 清空scanner中的resource和metadataReader之間的對應關系 //2. 設置applicationcontext中的初始狀態 //3. 打印啟動日志 //4. 設置env中的servletContext和serveltConfig //5. 驗證是否缺失了必須配置的參數this.prepareRefresh();//ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();this.prepareBeanFactory(beanFactory);try {this.postProcessBeanFactory(beanFactory);this.invokeBeanFactoryPostProcessors(beanFactory);this.registerBeanPostProcessors(beanFactory);this.initMessageSource();this.initApplicationEventMulticaster();this.onRefresh();this.registerListeners();this.finishBeanFactoryInitialization(beanFactory);this.finishRefresh();} catch (BeansException var9) {if (this.logger.isWarnEnabled()) {this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);}this.destroyBeans();this.cancelRefresh(var9);throw var9;} finally {this.resetCommonCaches();}}}

    為刷新context做準備: prepareRefresh()

    //AnnotationConfigEmbeddedWebApplicationContext protected void prepareRefresh() {this.scanner.clearCache();super.prepareRefresh();//調用AbstractApplicationContext中的prepareRefresh();}

    應該記得在構造函數中創建的ClassPathBeanDefinitionScanner。?

    在ClassPathBeanDefinitionScanner持有了一個Map:Resource, MetadataReader metadataReaderCache,用來保存resource和metadataReader;?
    scanner.clearCache()即清空該map的元素

    //AbstractApplicationContext.java protected void prepareRefresh() {this.startupDate = System.currentTimeMillis();this.closed.set(false);//設置application狀態this.active.set(true);//設置application狀態if (this.logger.isInfoEnabled()) {this.logger.info("Refreshing " + this);}this.initPropertySources();//調用的是GenericApplicationContext中的方法this.getEnvironment().validateRequiredProperties();//檢查是否缺失了必須配置的屬性this.earlyApplicationEvents = new LinkedHashSet();//初始化}
  • initPropertySources
  • //GenericApplicationContext.java protected void initPropertySources() {ConfigurableEnvironment env = this.getEnvironment();if (env instanceof ConfigurableWebEnvironment) {((ConfigurableWebEnvironment)env).initPropertySources(this.servletContext, (ServletConfig)null);//使用這里的servletContext和servletConfig來替換env中的propertySources}}
  • this.getEnvironment().validateRequiredProperties();?
    回顧env的類圖。查看代碼,可發現validateRequiredProperties是調用了AbstractProportyReslover.validateRequiredProperties()方法.作用是檢查是否缺失了必須配置的屬性?
  • public void validateRequiredProperties() {MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();Iterator var2 = this.requiredProperties.iterator();while(var2.hasNext()) {String key = (String)var2.next();if (this.getProperty(key) == null) {ex.addMissingRequiredProperty(key);}}if (!ex.getMissingRequiredProperties().isEmpty()) {throw ex;}}

    回顧prepareRefresh()這一步的動作:?
    1. 清空scanner中的resource和metadataReader之間的對應關系?
    2. 設置applicationcontext中的初始狀態?
    3. 打印啟動日志?
    4. 設置env中的servletContext和serveltConfig?
    5. 驗證是否缺失了必須配置的參數

    獲取bean factory

    //AbstractApplicationContext protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {this.refreshBeanFactory();//刷新bean factoryConfigurableListableBeanFactory beanFactory = this.getBeanFactory();//獲取beanFactoryif (this.logger.isDebugEnabled()) {this.logger.debug("Bean factory for " + this.getDisplayName() + ": " + beanFactory);}return beanFactory;} //GenericApplicationContext.java protected final void refreshBeanFactory() throws IllegalStateException {if (!this.refreshed.compareAndSet(false, true)) {//bean factory值可以刷新一次throw new IllegalStateException("GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");} else {//設置beanFactory的serializationId和向//Map<String, Reference<DefaultListableBeanFactory>> serializableFactories添加serializationId, new WeakReference(this)this.beanFactory.setSerializationId(this.getId());}}

    準備bean factory

    protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {//設置類加載器beanFactory.setBeanClassLoader(this.getClassLoader());//BeanExpressionResolver的標準實現用來解析spring el表達式,可以使用#{bean.xxx}的方式來調用相關屬性值beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));//通過資源編輯器 操作一個給定的PropertyEditorRegistry.并在所有bean創建的過程中應用PropertyEditorRegistry.沒有用過?beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment()));//ApplicationContextAwareProcessor用于上下文回調,它是BeanPostProcessor的實現類,跟一下這個接口的兩個方法postProcessBeforeInitialization和postProcessAfterInitialization//如果Bean是EmbeddedValueResolverAware接口的實現類,則調用setEmbeddedValueResolver方法,傳入當前BeanFactory//如果Bean是ResourceLoaderAware接口的實現類,則調用setResourceLoader方法,傳入當前上下文ApplicationContext//如果Bean是ApplicationEventPublisherAware的實現類,則調用setApplicationEventPublisher方法,傳入當前上下文ApplicationContext//如果Bean是MessageSourceAware的實現類,則調用setMessageSource方法,傳入當前上下文ApplicationContext//如果Bean是ApplicationContextAware的實現類,則調用setApplicationContext方法,傳入當前上下文ApplicationContext//https://www.cnblogs.com/xrq730/p/6670457.htmlbeanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));//定義了在依賴檢查和自動綁定時要忽略的依賴接口,是一組類對象,默認情況下,只有beanFactory接口被忽略。beanFactory.ignoreDependencyInterface(EnvironmentAware.class);beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);beanFactory.ignoreDependencyInterface(MessageSourceAware.class);beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);//根據第二個參數注冊一個特殊的依賴類型,意思是修正依賴,這里是一些自動裝配的特殊規則,比如是BeanFactory接口的實現類,則修正為當前BeanFactorybeanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);beanFactory.registerResolvableDependency(ResourceLoader.class, this);beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);beanFactory.registerResolvableDependency(ApplicationContext.class, this);beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));if (beanFactory.containsBean("loadTimeWeaver")) {beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));}//注冊enviroment單例if (!beanFactory.containsLocalBean("environment")) {beanFactory.registerSingleton("environment", this.getEnvironment());}//注冊systemProperties單例if (!beanFactory.containsLocalBean("systemProperties")) {beanFactory.registerSingleton("systemProperties", this.getEnvironment().getSystemProperties());}//注冊systemEnvironment單例if (!beanFactory.containsLocalBean("systemEnvironment")) {beanFactory.registerSingleton("systemEnvironment", this.getEnvironment().getSystemEnvironment());}}

    PostProcessorBeanFactory

    //添加beanPostProcessor由于這里的basePackages為null,所以并不掃描 //這一步的作用主要是注冊BeanPostProcessors //AnnotationConfigEmbeddedWebApplicationContext.java protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {super.postProcessBeanFactory(beanFactory);if (this.basePackages != null && this.basePackages.length > 0) {this.scanner.scan(this.basePackages);}if (this.annotatedClasses != null && this.annotatedClasses.length > 0) {this.reader.register(this.annotatedClasses);}} //EmbeddedWebApplicationContext.java protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));beanFactory.ignoreDependencyInterface(ServletContextAware.class);}

    invokeBeanFactoryPostProcessors

    主要是實例化和調用所有已注冊的BeanFactoryPostProcessors.需要在所有的bean實例化之前調用。?
    這個是整個Spring流程中非常重要的一部分,是Spring留給用戶的一個非常有用的擴展點,BeanPostProcessor接口針對的是每個Bean初始化前后做的操作而BeanFactoryPostProcessor接口針對的是所有Bean實例化前的操作

    關于如何使用BeanFactoryPostProcessors作為擴展點,可以參考這篇博文容器擴展點BeanFactoryPostProcessors

    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors());if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean("loadTimeWeaver")) {beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));}}

    這里委托了PostProcessorRegistrationDelegate工具類來調用BeanFactoryPostProcessor

    public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {// Invoke BeanDefinitionRegistryPostProcessors first, if any.// 如果有BeanDefinitionRegistryPostProcessors 的話,就先調用它們// 處理過的BeansSet<String> processedBeans = new HashSet<String>();// 是否是BeanDefinitionRegistry類型的BeanFactory. BeanDefinitionRegistry的作用是可以用來注冊,刪除,獲取BeanDefinitionsif (beanFactory instanceof BeanDefinitionRegistry) {BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;// 普通類型的BeanFactoryPostProcessor集合List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>();// BeanDefinitionRegistry類型的BeanFactoryPostProcessor集合(BeanDefinitionRegistryPostProcessor繼承于BeanFactoryPostProcessor)List<BeanDefinitionRegistryPostProcessor> registryPostProcessors =new LinkedList<BeanDefinitionRegistryPostProcessor>();// 對集合beanFactoryPostProcessors進行分類,如果是BeanDefinitionRegistry類型的BeanFactoryPostProcessor;則調用方法 - postProcessBeanDefinitionRegistry()。// postProcessBeanDefinitionRegistry(BeanDefinitionRegistry)該方法的作用是在標準的BeanDefinitions初始化完成后可以修改容器上下文內部的beanDefinition。for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {BeanDefinitionRegistryPostProcessor registryPostProcessor =(BeanDefinitionRegistryPostProcessor) postProcessor;registryPostProcessor.postProcessBeanDefinitionRegistry(registry);registryPostProcessors.add(registryPostProcessor);}else {regularPostProcessors.add(postProcessor);}}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!// Separate between BeanDefinitionRegistryPostProcessors that implement// PriorityOrdered, Ordered, and the rest.// 這里不要初始化FactoryBeans,//我們需要保留這些普通的beans 不在這里初始化,目的是為了讓bean factory post-processor去處理他們。// 根據BeanDefinitionRegistryPostProcessors 實現的不同接口PriorityOrdered,Ordered,或者不實現兩者,拆分開來去調用他們。String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.// 首先,調用實現了優先級接口 - PriorityOrdered的BeanDefinitionRegistryPostProcessors List<BeanDefinitionRegistryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();for (String ppName : postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}// 排序sortPostProcessors(beanFactory, priorityOrderedPostProcessors);// 添加排序好的優先級PostProcessors到registryPostProcessors集合registryPostProcessors.addAll(priorityOrderedPostProcessors);// 調用排序好的優先級BeanDefinitionRegistryPostProcessors,postProcessBeanDefinitionRegistry方法會被調用,用來修改,獲取,刪除容器上下文中的bean定義。//!!!!!這里是比較重要的一個點。priorityOrderedPostProcessors因為包含ConfigurationClassPostProcessor所以掃描了根目錄下的所有類,加載了對應的bean定義之所以從這個步驟中取到了 ConfigurationClassPostProcessor,是因為當初AnnotatedBeanDefinitionReader只注冊了bean definition。 invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.// 調用實現了Ordered接口的BeanDefinitionRegistryPostProcessors ,大致邏輯同上PriorityOrdered的處理postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);List<BeanDefinitionRegistryPostProcessor> orderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {orderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(beanFactory, orderedPostProcessors);registryPostProcessors.addAll(orderedPostProcessors);invokeBeanDefinitionRegistryPostProcessors(orderedPostProcessors, registry);// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.// 調用所有其它類型的BeanDefinitionRegistryPostProcessorsboolean reiterate = true;while (reiterate) {reiterate = false;postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName)) {BeanDefinitionRegistryPostProcessor pp = beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class);registryPostProcessors.add(pp);processedBeans.add(ppName);pp.postProcessBeanDefinitionRegistry(registry);reiterate = true;}}}// Now, invoke the postProcessBeanFactory callback of all processors handled so far.// 調用所有的BeanDefinitionRegistryPostProcessor的postProcessBeanFactory 方法。invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory);// 調用容器中BeanFactoryPostProcessor類型的bean(不包含BeanDefinitionRegistryPostProcessor類型的beans)。invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);}else {// Invoke factory processors registered with the context instance.// 若beanFactory不是BeanDefinitionRegistry類型的,則直接調用容器中所有的BeanFactoryPostProcessor的postProcessBeanFactory 方法。invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,// Ordered, and the rest.//將BeanFactoryPostProcessors分為3類,PriorityOrdered,Ordered,其他List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();List<String> orderedPostProcessorNames = new ArrayList<String>();List<String> nonOrderedPostProcessorNames = new ArrayList<String>();for (String ppName : postProcessorNames) {if (processedBeans.contains(ppName)) {//如果前面已經處理過過postprocessor,則跳過// skip - already processed in first phase above}else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));}else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {orderedPostProcessorNames.add(ppName);}else {nonOrderedPostProcessorNames.add(ppName);}}// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.//首先處理實現了PriorityOrdered接口的postProcessorsortPostProcessors(beanFactory, priorityOrderedPostProcessors);invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);// Next, invoke the BeanFactoryPostProcessors that implement Ordered.//其次處理實現了Ordered接口的postprocessorList<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();for (String postProcessorName : orderedPostProcessorNames) {orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}sortPostProcessors(beanFactory, orderedPostProcessors);invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);// Finally, invoke all other BeanFactoryPostProcessors.//最終調用其他的postprocessorList<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();for (String postProcessorName : nonOrderedPostProcessorNames) {nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);// Clear cached merged bean definitions since the post-processors might have// modified the original metadata, e.g. replacing placeholders in values...//postprocessor可能更改了原始數據的bean definition。所以清空緩存beanFactory.clearMetadataCache();}

    priorityOrderedPostProcessors因為包含ConfigurationClassPostProcessor所以掃描了根目錄下的所有類,加載了對應的bean定義。而在加載bean definition的時候,將自動配置的bean defintion也加載了進來。?
    invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);

    我們需要了解一下ConfigurationClassPostProcessor類的processConfigBeanDefinitions方法。

    public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {//候選的待解析的含有@Configuration注解的類List<BeanDefinitionHolder> configCandidates = new ArrayList();//從現有的的bean definition中獲取待解析類的nameString[] candidateNames = registry.getBeanDefinitionNames();String[] var4 = candidateNames;int var5 = candidateNames.length;for(int var6 = 0; var6 < var5; ++var6) {String beanName = var4[var6];BeanDefinition beanDef = registry.getBeanDefinition(beanName);//如果當前的beanDef即不是full,也不是lite//在沒有checkConfigurationClassCandidate之前,beanDef的CONFIGURATION_CLASS_ATTRIBUTE屬性是沒有設置的if (!ConfigurationClassUtils.isFullConfigurationClass(beanDef) && !ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {//如果beanDef有@Configuration注解,則設置CONFIGURATION_CLASS_ATTRIBUTE為full,返回true//如果beanDef有Component,ComponentScan,Import,ImportResource注解中的一個,則CONFIGURATION_CLASS_ATTRIBUTE設置為lite,返回true//返回true,則加入configCandidatesif (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));}} else if (this.logger.isDebugEnabled()) {this.logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);}}if (!configCandidates.isEmpty()) {//首先對configCandidates進行排序Collections.sort(configCandidates, new Comparator<BeanDefinitionHolder>() {public int compare(BeanDefinitionHolder bd1, BeanDefinitionHolder bd2) {int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());return i1 < i2 ? -1 : (i1 > i2 ? 1 : 0);}});SingletonBeanRegistry sbr = null;if (registry instanceof SingletonBeanRegistry) {sbr = (SingletonBeanRegistry)registry;//如果當前沒有設置過beanNameGenerator,則設置if (!this.localBeanNameGeneratorSet && sbr.containsSingleton("org.springframework.context.annotation.internalConfigurationBeanNameGenerator")) {BeanNameGenerator generator = (BeanNameGenerator)sbr.getSingleton("org.springframework.context.annotation.internalConfigurationBeanNameGenerator");this.componentScanBeanNameGenerator = generator;this.importBeanNameGenerator = generator;}}//創建ConfigurationClass的解析器ConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry);//待解析的configurationClass的bean defSet<BeanDefinitionHolder> candidates = new LinkedHashSet(configCandidates);//已經解析過的,元素為ConfigurationClassHashSet alreadyParsed = new HashSet(configCandidates.size());do {//解析parser.parse(candidates);parser.validate();//在解析的過程中會遇到很多的需要依賴的bean defSet<ConfigurationClass> configClasses = new LinkedHashSet(parser.getConfigurationClasses());configClasses.removeAll(alreadyParsed);//去重if (this.reader == null) {this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment, this.importBeanNameGenerator, parser.getImportRegistry());}//加載這些依賴的bean defthis.reader.loadBeanDefinitions(configClasses);alreadyParsed.addAll(configClasses);candidates.clear();//如果registry中的bean def的數量比candidateNames要多,說明還有一些bean def沒有被處理。if (registry.getBeanDefinitionCount() > candidateNames.length) {String[] newCandidateNames = registry.getBeanDefinitionNames();Set<String> oldCandidateNames = new HashSet(Arrays.asList(candidateNames));Set<String> alreadyParsedClasses = new HashSet();Iterator var12 = alreadyParsed.iterator();while(var12.hasNext()) {ConfigurationClass configurationClass = (ConfigurationClass)var12.next();alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());}String[] var23 = newCandidateNames;int var24 = newCandidateNames.length;for(int var14 = 0; var14 < var24; ++var14) {String candidateName = var23[var14];//如果之前沒有遇到過這個候選的bean nameif (!oldCandidateNames.contains(candidateName)) {BeanDefinition bd = registry.getBeanDefinition(candidateName);//如果這個類含有對應的注解,且沒有被解析過,則加入到candidates中if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) && !alreadyParsedClasses.contains(bd.getBeanClassName())) {candidates.add(new BeanDefinitionHolder(bd, candidateName));}}}candidateNames = newCandidateNames;}} while(!candidates.isEmpty());if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());}if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {((CachingMetadataReaderFactory)this.metadataReaderFactory).clearCache();}}}

    我們需要關注的是其中的兩行代碼:parser.parse(candidates);用來解析候選類。在解析候選類的過程中會遇到很多以來的bean definition,this.reader.loadBeanDefinitions(configClasses);將注冊新發現的bean defintion

    parser.parse(candidates);parser.validate();//在解析的過程中會遇到很多的需要依賴的bean defSet<ConfigurationClass> configClasses = new LinkedHashSet(parser.getConfigurationClasses());configClasses.removeAll(alreadyParsed);//去重if (this.reader == null) {this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment, this.importBeanNameGenerator, parser.getImportRegistry());}//加載這些依賴的bean defthis.reader.loadBeanDefinitions(configClasses);

    ConfigurationClassParser用來解析一個beanDefition。因為在這次的場景中只有AppBootStrap這一個類。我們就從ConfigurationClassParser對這一個類的解析來說。

    注冊beanPostProcessor

    將beanPostProcessor分為4類,實現了PriorityOrdered接口的,實現了Ordered接口的,兩者都沒有實現的,是MergedBeanDefinitionPostProcessor的。這4類分別排序,被添加進入beanFactory的一個beanPostProcessor的list中,這里并不會調用BeanPostProcessor接口的方法。到時候在bean的初始化前后按順序調用他們

    這里就根據代碼總結一下BeanPostProcessor接口的調用順序:

  • 優先調用PriorityOrdered接口的子接口,調用順序依照接口方法getOrder的返回值從小到大排序
  • 其次調用Ordered接口的子接口,調用順序依照接口方法getOrder的返回值從小到大排序
  • 接著按照BeanPostProcessor實現類在配置文件中定義的順序進行調用
  • 最后調用MergedBeanDefinitionPostProcessor接口的實現Bean,同樣按照在配置文件中定義的順序進行調用
  • public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;beanFactory.addBeanPostProcessor(new PostProcessorRegistrationDelegate.BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList();List<BeanPostProcessor> internalPostProcessors = new ArrayList();List<String> orderedPostProcessorNames = new ArrayList();List<String> nonOrderedPostProcessorNames = new ArrayList();String[] var8 = postProcessorNames;int var9 = postProcessorNames.length;String ppName;BeanPostProcessor pp;for(int var10 = 0; var10 < var9; ++var10) {ppName = var8[var10];if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {pp = (BeanPostProcessor)beanFactory.getBean(ppName, BeanPostProcessor.class);priorityOrderedPostProcessors.add(pp);if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}} else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {orderedPostProcessorNames.add(ppName);} else {nonOrderedPostProcessorNames.add(ppName);}}sortPostProcessors(beanFactory, priorityOrderedPostProcessors);registerBeanPostProcessors(beanFactory, (List)priorityOrderedPostProcessors);List<BeanPostProcessor> orderedPostProcessors = new ArrayList();Iterator var14 = orderedPostProcessorNames.iterator();while(var14.hasNext()) {String ppName = (String)var14.next();BeanPostProcessor pp = (BeanPostProcessor)beanFactory.getBean(ppName, BeanPostProcessor.class);orderedPostProcessors.add(pp);if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}}sortPostProcessors(beanFactory, orderedPostProcessors);registerBeanPostProcessors(beanFactory, (List)orderedPostProcessors);List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList();Iterator var17 = nonOrderedPostProcessorNames.iterator();while(var17.hasNext()) {ppName = (String)var17.next();pp = (BeanPostProcessor)beanFactory.getBean(ppName, BeanPostProcessor.class);nonOrderedPostProcessors.add(pp);if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}}registerBeanPostProcessors(beanFactory, (List)nonOrderedPostProcessors);sortPostProcessors(beanFactory, internalPostProcessors);registerBeanPostProcessors(beanFactory, (List)internalPostProcessors);beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));}

    initMessageSource用于創建messageSource

    initApplicationEventMulticaster用于創建上下文事件廣播器

    onRefresh創建Web容器

    首先 onfresh():?
    一個模板方法,重寫它的作用是添加特殊上下文刷新的工作,在特殊Bean的初始化時、初始化之前被調用。在Spring中,AbstractRefreshableWebApplicationContext、GenericWebApplicationContext、StaticWebApplicationContext都實現了這個方法。這三個類都是用它來配置themeSource。在EmbeddedWebApplicationContext中則創建和啟動了servlet容器。需要在bean實例化之前創建servletcontainer

    //EmbeddedWebApplicationContext.java protected void onRefresh() {super.onRefresh();try {this.createEmbeddedServletContainer();//} catch (Throwable var2) {throw new ApplicationContextException("Unable to start embedded container", var2);}}private void createEmbeddedServletContainer() {EmbeddedServletContainer localContainer = this.embeddedServletContainer;ServletContext localServletContext = this.getServletContext();if (localContainer == null && localServletContext == null) {//如果用戶有配置過,則使用用戶配置的containerFactory,否則使用默認的。EmbeddedServletContainerFactory containerFactory = this.getEmbeddedServletContainerFactory();//獲取到containerFactory之后就可以使用containerFactory獲取servletContainer。//而這里在獲取servletContainer的時候,直接啟動了Jetty中的server//另外還需要關注的是我們傳遞了一個initailizer進去this.embeddedServletContainer = containerFactory.getEmbeddedServletContainer(new ServletContextInitializer[]{this.getSelfInitializer()});} else if (localServletContext != null) {try {this.getSelfInitializer().onStartup(localServletContext);} catch (ServletException var4) {throw new ApplicationContextException("Cannot initialize servlet context", var4);}}//重新設置context中和servlet有關的幾個屬性this.initPropertySources();}protected EmbeddedServletContainerFactory getEmbeddedServletContainerFactory() {//如果配置了JettyConfig,則是我們配置的那個,否在是通過自動配置注入進來的//如果沒有配置過,且有Jetty,則是jettyEmbeddedServletContainerFactoryString[] beanNames = this.getBeanFactory().getBeanNamesForType(EmbeddedServletContainerFactory.class);if (beanNames.length == 0) {throw new ApplicationContextException("Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.");} else if (beanNames.length > 1) {throw new ApplicationContextException("Unable to start EmbeddedWebApplicationContext due to multiple EmbeddedServletContainerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));} else {return (EmbeddedServletContainerFactory)this.getBeanFactory().getBean(beanNames[0], EmbeddedServletContainerFactory.class);}} //JettyEmbeddedServletContainerFactory.class public EmbeddedServletContainer getEmbeddedServletContainer(ServletContextInitializer... initializers) {JettyEmbeddedWebAppContext context = new JettyEmbeddedWebAppContext();int port = this.getPort() >= 0 ? this.getPort() : 0;InetSocketAddress address = new InetSocketAddress(this.getAddress(), port);Server server = this.createServer(address);this.configureWebAppContext(context, initializers);server.setHandler(this.addHandlerWrappers(context));this.logger.info("Server initialized with port: " + port);if (this.getSsl() != null && this.getSsl().isEnabled()) {SslContextFactory sslContextFactory = new SslContextFactory();this.configureSsl(sslContextFactory, this.getSsl());AbstractConnector connector = this.getSslServerConnectorFactory().getConnector(server, sslContextFactory, port);server.setConnectors(new Connector[]{connector});}Iterator var8 = this.getServerCustomizers().iterator();while(var8.hasNext()) {JettyServerCustomizer customizer = (JettyServerCustomizer)var8.next();customizer.customize(server);}if (this.useForwardHeaders) {(new JettyEmbeddedServletContainerFactory.ForwardHeadersCustomizer(null)).customize(server);}return this.getJettyEmbeddedServletContainer(server);}protected JettyEmbeddedServletContainer getJettyEmbeddedServletContainer(Server server) {return new JettyEmbeddedServletContainer(server, this.getPort() >= 0);} //JettyEmbeddedServletContainer.java public JettyEmbeddedServletContainer(Server server, boolean autoStart) {this.monitor = new Object();this.autoStart = autoStart;Assert.notNull(server, "Jetty Server must not be null");this.server = server;this.initialize();}private void initialize() {Object var1 = this.monitor;synchronized(this.monitor) {try {this.connectors = this.server.getConnectors();this.server.addBean(new AbstractLifeCycle() {protected void doStart() throws Exception {Connector[] var1 = JettyEmbeddedServletContainer.this.connectors;int var2 = var1.length;for(int var3 = 0; var3 < var2; ++var3) {Connector connector = var1[var3];Assert.state(connector.isStopped(), "Connector " + connector + " has been started prematurely");}JettyEmbeddedServletContainer.this.server.setConnectors((Connector[])null);}});this.server.start();//這里啟動了jettythis.server.setStopAtShutdown(false);} catch (Exception var4) {this.stopSilently();throw new EmbeddedServletContainerException("Unable to start embedded Jetty servlet container", var4);}}}

    我們在創建ServletContainer的時候,傳遞了一個initializer進去。在servlet容器創建后執行一些初始化動作

    private void selfInitialize(ServletContext servletContext) throws ServletException {//我們需要重點關注這個方法this.prepareEmbeddedWebApplicationContext(servletContext);ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();EmbeddedWebApplicationContext.ExistingWebApplicationScopes existingScopes = new EmbeddedWebApplicationContext.ExistingWebApplicationScopes(beanFactory);WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.getServletContext());existingScopes.restore();WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.getServletContext());Iterator var4 = this.getServletContextInitializerBeans().iterator();while(var4.hasNext()) {ServletContextInitializer beans = (ServletContextInitializer)var4.next();beans.onStartup(servletContext);}}//關注這個方法的原因是我們在這個方法中設置了servletContext的ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE屬性為我們之前applicationContext,也設置了我們applicationContext中的serveltContext屬性為在創建servlet容器時創建的servletContext protected void prepareEmbeddedWebApplicationContext(ServletContext servletContext) {Object rootContext = servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);if (rootContext != null) {if (rootContext == this) {throw new IllegalStateException("Cannot initialize context because there is already a root application context present - check whether you have multiple ServletContextInitializers!");}} else {Log logger = LogFactory.getLog(ContextLoader.class);servletContext.log("Initializing Spring embedded WebApplicationContext");try {servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this);if (logger.isDebugEnabled()) {logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");}this.setServletContext(servletContext);if (logger.isInfoEnabled()) {long elapsedTime = System.currentTimeMillis() - this.getStartupDate();logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");}} catch (RuntimeException var6) {logger.error("Context initialization failed", var6);servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, var6);throw var6;} catch (Error var7) {logger.error("Context initialization failed", var7);servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, var7);throw var7;}}}

    AfterFresh

    spring boot在這一步中完成對Runners的調用?
    參考CommandLineRunner,ApplicationRunner

    protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {this.callRunners(context, args);}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);Iterator var4 = (new LinkedHashSet(runners)).iterator();while(var4.hasNext()) {Object runner = var4.next();if (runner instanceof ApplicationRunner) {this.callRunner((ApplicationRunner)runner, args);}if (runner instanceof CommandLineRunner) {this.callRunner((CommandLineRunner)runner, args);}}}

    參考資料

    講bean definition的加載過程的更詳細的一篇博文?
    spring boot源碼解析專欄?
    PostProcessorRegistrationDelegate?
    詳解ImportSelector接口?
    關于springboot 的啟動流程?
    BeanPostProcessor擴展點?
    非懶加載bean初始化的過程,特別贊,作者還有關于spring的一系列的文章,建議可以去看?
    refresh方法?
    Jetty的工作原理?
    Spring中的bean工廠后置處理器

    總結

    以上是生活随笔為你收集整理的springboot启动流程的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。