spring boot原理分析(八):上下文Context即世界1

前言

    上下文Context可以說spring boot中最重要的一個概念,不僅包含了tomcat和spring mvc的啓動和管理,還對spring mvc原有模式中的bean註冊進行了大幅簡化,理解Spring boot的Context可以說是理解spring boot的基礎。
    原理分析(六)介紹了spring boot啓動的主流程,run方法中最主要的部分即上下文的準備。

public ConfigurableApplicationContext run(String... args) {
    ......
    context = createApplicationContext();
    exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
        new Class[] { ConfigurableApplicationContext.class }, context);
    prepareContext(context, environment, listeners, applicationArguments, printedBanner);
    refreshContext(context);
    afterRefresh(context, applicationArguments);
    stopWatch.stop();
    ......
  return context;
}

上文代碼中包括context的創建、準備、刷新和刷新後處理。刷新後處理的方法afterRefresh是模板方法,供子類繼承填充代碼邏輯。

上下文創建

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);
}

    上下文創建createApplicationContext還是會依據SERVLET、REACTIVE和NONE類型來創建相應的上下文。類型解釋再引用一下原理分析(六)的內容。

SERVLET、REACTIVE和NONE。我們講spring mvc是Servlet容器,所以服務即SERVLET WEB類型。REACTIVE也是一種WEB服務的類型,代表着非阻塞響應式編程,正是spirng mvc不擅長的事,具體可以參考spring-webflux。NONE類型說這個服務不是WEB類型,是其他服務類型。

Servlet服務對應的環境上下文是AnnotationConfigServletWebServerApplicationContext類,Reactive服務對應的環境上下文是AnnotationConfigReactiveWebServerApplicationContext類,而默認的上下文AnnotationConfigApplicationContext類。

上下文Context的定義

    根據ApplicationContext接口定義可以發現上下文的本質其實是一個“雜貨鋪”,繼承的父類顯示了上下文中包含的內容。

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
		MessageSource, ApplicationEventPublisher, ResourcePatternResolver {

	@Nullable
	String getId();

	String getApplicationName();

	String getDisplayName();

	long getStartupDate();

	@Nullable
	ApplicationContext getParent();

	AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;

}
  • 繼承的父類接口EnvironmentCapable賦予了上下文獲取應用程序的運行環境配置的能力。環境配置包括profile和properties配置,properties配置不僅包括項目內的properties文件,還有JVM system properties、操作系統環境變量等。
  • ListableBeanFactory和HierarchicalBeanFactory賦予了上下文獲取bean、註冊bean的能力。
  • MessageSource主要是國際化配置,比如語言等
  • ApplicationEventPublisher提供了上下文發送上下文狀態改變事件的能力。這部分內容在原理分析(七)中有比較詳細的介紹。
  • ResourcePatternResolver繼承了ResourceLoader,是用來做資源的格式解析,比如各種配置文件等等。

這裏需要注意的是,ApplicationContext接口中定義的都是getter類型的接口方法,沒有setter類型的接口方法。這是因爲不是所有上下文對象都提供修改內容的接口方法,只有ConfigurableApplicationContext接口的實現類提供了setter方法,可以修改上下文中的配置。這樣做是爲了防止上下文內容被隨意變更。

上下文Context的實現

spring boot原理分析(八):上下文Context即世界1-AnnotationConfigServletWebServerApplicationContext.png     SERVLET上下文的最終實現是AnnotationConfigServletWebServerApplicationContext類,上圖展示了這個類的繼承結構。

    在ApplicationContext的更上層是基礎層的接口,上面已經介紹了,這些接口打包構成了上下文的“雜貨鋪”。ApplicationContext下層是其不同類型的子接口或者子類,主要是根據功能或者應用對象對上下文進行了分類。
    WebApplicationContext接口添加了ServletContext getServletContext()方法。ServletContext的相關內容在spring mvc的原理(七)中,ServletConfig能夠獲取ServletContext的配置,其實代表就是spring mvc的應用本身。
    WebServerApplicationContext的接口裏增加了WebServer getWebServer()的方法,這裏具體代表的就是tomcat服務器本身。
    ConfigurableApplicationContext上面已經介紹過,是一個功能性的子接口,爲ApplicationContext提供了setter的方法,所有有繼承改接口的子類都擁有修改配置的能力。
    所以這樣就很容易判斷ConfigurableWebApplicationContext和ConfigurableWebServerApplicationContext具有的能力,實際上是功能分類和應用對象分類的一個拼合。
    接下來比較重要的是GenericApplicationContext,這個子類的特別之處在於繼承了bean定義的註冊BeanDefinitionRegistry。BeanDefinitionRegistry在原理分析(三)有過介紹,是用來用來註冊bean的。GenericApplicationContext的使用方法的官方解釋是,先使用BeanDefinitionRegistry註冊一系列的bean,然後調用 AbstractApplicationContext.refresh()初始化這些bean。與普通ApplicationContext的實現類不同的是,GenericApplicationContext不會每次refresh創建一個新的BeanFactory實例,而是在構造時就會獲取並持有一個BeanFactory實例,AbstractApplicationContext.refresh()可能只會被調用一次。
    使用以上子類或者子接口的功能進行拼合,就得出了GenericWebApplicationContext和ServletWebServerApplicationContext這兩個類。
    最後對於AnnotationConfigServletWebServerApplicationContext,除了上述所有子接口和子類的功能之外,還實現了AnnotationConfigRegistry接口。AnnotationConfigRegistry這個接口主要是負責bean註解的註冊和掃描工作,比如@Configuration註解。

    本文主要介紹了Spring boot的ApplicationContext的定義實現和創建,後續會對上下文的準備和刷新進行介紹。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章