Spring context架構--靜態結構

概念

Context也就是我們常說的spring容器,打個比方,context就像是一家公司,beans則是公司的工廠,除了工廠,公司還有翻譯,倉庫以及辦公場所等等。

下面就看看context的主要構成部件。

Context構成部件

spring context

上圖是ApplicationContext的實體靜態結構,它繼承了六個實體。雖然是繼承,但其實context和他們的關係更像是聚合。Spring使用繼承主要是爲了在context上也同時體現這6個實體的特徵。在實現層面,context事實上是個包裝類,最終通過聚合的實體類完成相應行爲,而ApplicationContext接口本身並沒有什麼實質意義的方法。

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

    String getId();

    String getApplicationName();

    String getDisplayName();

    long getStartupDate();

    ApplicationContext getParent();

    AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}

ApplicationContext的實質功能都是繼承於以下6個實體:

  1. MessageSource: 用於國際化的接口,可以將其理解爲公司的翻譯。用戶可以通過bean配置自定義MessageSource–要求name爲“messageSource”,spring會在容器refresh時自動探測並且初始化它。

  2. ApplicationEventPublisher: 用於發佈應用事件,例如ContextRefreshed,stopped, started等。它就像是企業郵箱,通過它可以接收到公司的事件通知。用戶通過配置ApplicationListener類型的bean即可訂閱這類事件,spring通過getBeansOfType取得所有的listener,並依次通知。

  3. ResourcePatternResolver: 對ResourceLoader的擴展,後者只支持對具體路徑資源的加載,而前者則支持對某pattern路徑資源的加載,默認是ant風格的模式。Resource是特指配置文件,或者class路徑(裏的掃描路徑)。我們可以將它理解爲打單的機器,將各個地方發過來的單子打出來。

  4. ListableBeanFactory和HierachicalBeanFactory: 自然的context也是個工廠,context裏持有的依然是DefaultListableBeanFactory,通過它完成工廠的相應行爲。介紹下這兩個工廠,前者主要用於取得批量bean,比如getBeansOfType;後一個工廠則主要體現層級概念,但是context的parentFactory也是一個context,這是因爲context具有beanFactory的所有特徵。

  5. EnviromentCapable: 則類似是公司的行政部門,負責辦公場所等設施維護。它關聯着Enviroment。Enviroment也類似context是個包裝類,雖然繼承了PropertyResolver,但在實現類裏是委託給ConfigurablePropertyResolver處理的。Enviroment代表應用環境,比如測試環境還是生產環境又或者開發環境。
    用戶可以通過或者@Profile指定某個配置的profile。然後通過activeProfile指定應用環境,從而會enable相應profile的beans
    activeProfile可以通過5種方式指定:
    1). servlet config init param,這種方式只適用於spring mvc的dispatcherServlet配置上
    2). servlet context init param
    3). system property
    4). system env。以上四種方式設置的key均爲spring.profiles.active
    5.) @ActiveProfile,這種方式只適用於junit單元測試

Context通過繼承獲得了工廠,事件發佈,環境定義,資源加載以及國際化的能力。

context靜態結構

這一節我只抽一些比較重要的接口的源碼講述,主要還是注重概念和原理,後面會專門出一篇講context的動態處理過程,那裏面會對具體實現類做詳述。這一篇澤主要是建立對context靜態類結構的理解。

下圖是web application context的類圖,可以和構成部件的結構圖結合着看,上面的圖每個實體都是spring context的一個接口。
context類結構
常見的WebApplicationContext實現主要有兩個,分別是XmlWebApplicationContext和AnnotationConfigWebApplicationContext。他們共同的父類爲AbstractRefreshableWebApplicationContext,我們從它出發,看一下context的類結構。

LifeCycle和Closeable代表着容器的整個生命週期,被ConfigurableApplicationContext繼承,使繼承該接口的context具有生命週期的特徵。

public interface Lifecycle {
    void start();

    void stop();

    boolean isRunning();
}

用戶可以配置Lifecycle類型bean,在context start以及stop時也會相應的啓動LifeCycle bean的start或者stop。對於允許autoStartup的SmartLifecycle,context refresh的過程中會自動啓動。

ConfigurableApplicationContext繼承了生命週期,代表一個可以修改相關屬性行爲的context,上一節提到的Enviroment和ApplicationListener等等都可以通過它設置。同時整個context的核心refresh方法也是定義在他裏面,所以所有的context都繼承了它。

public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
       void setId(String id);

    void setParent(ApplicationContext parent);

    ConfigurableEnvironment getEnvironment();

    void setEnvironment(ConfigurableEnvironment environment);

//添加bean後處理器,[beans架構](http://blog.csdn.net/szwandcj/article/details/50688616)架構裏詳細講過後處理器
       void addBeanFactoryPostProcessor(BeanFactoryPostProcessor beanFactoryPostProcessor);

    void addApplicationListener(ApplicationListener<?> listener);

//context核心方法,refresh是整個容器構建的過程
    void refresh() throws BeansException, IllegalStateException;

//註冊jdk進程退出時的hook
    void registerShutdownHook();

    void close();

    boolean isActive();

    ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}

實現這個接口的AbstractApplicationContext很自然的也承擔了context的絕大部分職能,上一節提過的context的六個方面的功能就幾乎都是由它實現,除BeanFactory以外,其它的4個實體都是聚合在這個類裏。而DefaultListableBeanFactory–那個最著名的BeanFactory則是由它的子類AbstractRefreshableApplicationContext生成,它自己通過模板方法使用。

AbstractRefreshableApplicationContext定義了loadBeanDefinitions模板方法,由具體的實現提供。它創建bean factory並load配置文件。beans配置文件load過程參考這裏

AbstractRefreshableConfigApplicationContext主要用於設置資源的路徑。幾乎所有的ApplicationContext都會繼承這個類,除非不需要讀取配置資源。

AbstractRefreshableWebApplicationContext主要針對web的一些特性提供一些context屬性行爲設置能力,例如覆蓋默認的enviroment(默認的由AbstractApplicationContext提供),生成StandardServletEnviroment,又例如覆蓋ResourcePatternResolver以及對BeanFactory的後處理等。

ConfigurableWebApplicationContext則是web application context的通用接口,爲了支持spring-mvc和spring-web定義了一些set方法,例如設置configLocations(ConfigurableApplicationContext接口並不支持setConfigLocation,因爲這個接口是跟着ClassPathXmlApplicationContext一起發佈的,而web和mvc是後來加上的功能)和nameSpace等。可以把它看成是專門支持web和mvc的一個接口(web和mvc中生成context是通過class.newInstance的無參構造,所以無法將這些信息作爲參數傳入,必須顯示提供set方法以設置屬性)

public interface ConfigurableWebApplicationContext extends WebApplicationContext, ConfigurableApplicationContext {

    void setServletContext(ServletContext servletContext);

    void setServletConfig(ServletConfig servletConfig);

    ServletConfig getServletConfig();

    void setNamespace(String namespace);

    String getNamespace();

    void setConfigLocation(String configLocation);

    void setConfigLocations(String... configLocations);

    String[] getConfigLocations();
}

Enviroment實現

再具體說下Enviroment的實現,還是挺有意思的。下圖是enviroment的序列圖
enviroment

主要說下MutablePropertySources和PropertySource。

最終屬性值是通過PropertySource取得,它有多種實現,分別代表一種來源的屬性。第二節提到的4種來源則分別對應着ServletConfigPropertySource,ServletContextPropertySource,MapPropertySource和SystemEnvironmentPropertySource。

MutablePropertySources裏持有一個property的list,對它迭代直到從一個PropertySource裏取出對應key的值就停止,從這可以就看出spring.profiles.active是有先後優先級的。

有興趣的可以看下源碼,會稍微有些繁瑣。有一點需要注意:spring web和mvc模塊會在refresh applicationContext之前調用相應enviroment#initPropertySources生成ServletConfigPropertySource和ServletContextPropertySource。相應的MapPropertySource和SystemEnvironmentPropertySource則是默認生成的。所以如果不是web項目,就只能通過配置system properties或者env指定activeProfile。

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