1. 程式人生 > >【Spring原始碼分析系列】ApplicationContext 相關介面架構分析

【Spring原始碼分析系列】ApplicationContext 相關介面架構分析

在使用Spring的時候,我們經常需要先得到一個ApplicationContext物件,然後從該物件中獲取我們配置的Bean物件。ApplicationContext隸屬於org.springframework.context,是SpringFramework中Bean的管理者,為SpringFramework的諸多功能提供支撐作用。

下圖是Spring-4.3.2.RELEASE版本中ApplicationContext相關的UML類檢視(淺綠色的為介面,淺黃色的為類):

SpringApplicationContext

BeanFactory系列介面:

public interface BeanFactory

BeanFactory 是 Spring 管理 Bean 的最頂層介面,是一個 Bean 容器, 管理一系列的 bean,每一個 bean 使用一個String 型別的 name(或稱之為id) 來唯一確定,這些 Bean 可以是 prototype 的或者 singleton的 。Spring 提倡使用依賴注入(Dependency Injection) 的方式裝配 Bean。BeanFactory從“configuration source”載入Bean的定義,configuration source 可以是xml檔案或者properties檔案甚至是資料庫。

public interface HierarchicalBeanFactory extends BeanFactory

BeanFactory的子介面HierarchicalBeanFactory是一個具有層級關係的Bean 工廠,擁有屬性parentBeanFactory。當獲取 Bean物件時,如果當前BeanFactory中不存在對應的bean,則會訪問其直接 parentBeanFactory 以嘗試獲取bean 物件。此外,還可以在當前的 BeanFactory 中 override 父級BeanFactory的同名bean。

public interface ListableBeanFactory extends BeanFactory

ListableBeanFactory 繼承了BeanFactory,實現了列舉方法可以列舉出當前BeanFactory中所有的bean物件而不必根據name一個一個的獲取。 如果 ListableBeanFactory 物件還是一個HierarchicalBeanFactory則getBeanDefinitionNames()方法只會返回當前BeanFactory中的Bean物件而不會去父級BeanFactory中查詢。

其他介面:

public interface PropertyResolver

配置檔案解析器的最頂級介面,解析配置檔案獲取屬性值等作用

public interface Environment extends PropertyResolver

提供當前Application執行的所需環境

public interface EnvironmentCapable

這是一個Environment Holder,只有一個方法:Environment getEnvironment() 用來獲取Environment物件

public interface ApplicationEventPublisher

該介面的功能是publish Event,向事件監聽器(Listener)傳送事件訊息

public interface MessageSource

解析message的策略介面,方法形如: String getMessage(String, Object[], String, Locale),用於支撐國際化等功能

public interface ResourcePatternResolver extends ResourceLoader

其中ResourceLoader用於從一個源(如InputStream等)載入資原始檔,ResourcePatternResolver 是ResourceLoader的子類,根據 path-pattern 載入資源。

ApplicationContext介面:

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

重點來了,ApplicationContext介面繼承眾多介面,集眾多介面功能與一身,為Spring的執行提供基本的功能支撐。根據程式設計的“單一職責原則”,其實每個較頂層介面都是“單一職責的”,只提供某一方面的功能,而ApplicationContext介面繼承了眾多介面,相當於擁有了眾多介面的功能,下面看看它的主要功能:

  • 首先,它是個BeanFactory,可以管理、裝配bean,可以有父級BeanFactory實現Bean的層級管理(具體到這裡來說它可以有父級的ApplicationContext,因為ApplicationContext本身就是一個BeanFactory。這在web專案中很有用,可以使每個Servlet具有其獨立的context, 所有Servlet共享一個父級的context),它還是Listable的,可以枚舉出所管理的bean物件。
  • 其次,它是一個ResourceLoader,可以載入資原始檔;
  • 再次,它可以管理一些Message實現國際化等功能;
  • 還有,它可以釋出事件給註冊的Listener,實現監聽機制。

ApplicationContext 的子介面:

ApplicationContext 介面具有兩個直接子介面,分別是:

org.springframework.context.ConfigurableApplicationContext 
org.springframework.web.context.WebApplicationContext

分別看這兩個子介面:

public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable

根據介面名可以判決,該介面是可配置的!ApplicationContext 介面本身是 read-only 的,所以子介面 ConfigurableApplicationContext 就提供瞭如setID()、setParent()、setEnvironment()等方法,用來配置ApplicationContext。

再看其繼承的另外兩個介面:

  • Lifecycle:Lifecycle介面中具有start()、stop()等方法,用於對context生命週期的管理;
  • Closeable:Closeable是標準JDK所提供的一個介面,用於最後關閉元件釋放資源等;
public interface WebApplicationContext extends ApplicationContext

該介面僅僅在原介面基礎上提供了getServletContext(),用於給servlet提供上下文資訊。

public interface ConfigurableWebApplicationContext extends WebApplicationContext, ConfigurableApplicationContext

這裡 ConfigurableWebApplicationContext 又將上述兩個介面結合起來,提供了一個可配置、可管理、可關閉的WebApplicationContext,同時該介面還增加了setServletContext(),setServletConfig()等set方法,用於裝配WebApplicationContext。

到這裡ApplicationContext相關介面基本上已經講完了,總結起來就兩大介面:

org.springframework.context.ConfigurableApplicationContext 
org.springframework.web.context.ConfigurableWebApplicationContext

對於普通應用,使用ConfigurableApplicationContext 介面的實現類作為bean的管理者,對於web應用,使用ConfigurableWebApplicationContext 介面的實現類作為bean的管理者。這兩個介面,從結構上講他們是繼承關係,從應用上講他們是平級關係,在不同的領域為Spring提供強大的支撐。  

ApplicationContext相關實現類設計:

Spring是一個優秀的框架,具有良好的結構設計和介面抽象,它的每一個介面都是其功能具體到各個模組中的高度抽象,實際使用過程中相當於把介面的各個實現類按照介面所提供的組織架構裝配起來以提供完整的服務,可以說掌握了Spring的介面就相當於掌握了Spring的大部分功能。

ApplicationContext 的實現類眾多,然而

上文中分析了 ApplicationContext 介面的各個功能,下面將分析 ApplicationContext 的實現類對上述介面的各個功能都是怎樣實現的(PS. 限於篇幅,這裡僅僅指出上述各個功能在實現類中什麼位置通過什麼方法實現,至於其具體實現過程,每一個功能拿出來都可以單獨寫一篇文章了,這裡不進行詳述)。至於實現類又擴充套件了其他介面或者繼承了其他父類,這些只是實現類為了擴充套件功能或者為了對實現上述介面提供便利而做的事情,對ApplicationContext介面抽象出來的功能沒有影響或者沒有太大幫助,因此略去。

以ClassPathXmlApplicationContext為例,其主要繼承關係如下:

org.springframework.context.support.AbstractApplicationContext 
      org.springframework.context.support.AbstractRefreshableApplicationContext 
            org.springframework.context.support.AbstractRefreshableConfigApplicationContext 
                  org.springframework.context.support.AbstractXmlApplicationContext 
                        org.springframework.context.support.ClassPathXmlApplicationContext

而最頂層抽象類 AbstractApplicationContext 又實現了 ConfigurableApplicationContext 介面。

AbstractApplicationContext extends DefaultResourceLoader    implements ConfigurableApplicationContext, DisposableBean

根據上文所述,這裡略去其父類 DefaultResourceLoader 和介面 DisposableBean ,只關注介面 ConfigurableApplicationContext,回憶一下該的主要功能:

Configable, //可配置(該介面本身擴充套件的功能)
Lifecycle, //生命週期可管理 
Closeable,//可關閉(釋放資源) 
EnvironmentCapable,//可配置Environment 
MessageSource, //可管理message實現國際化等功能
ApplicationEventPublisher, //可publish事件,呼叫Listener 
ResourcePatternResolver,//載入pattern指定的資源 
ListableBeanFactory, HierarchicalBeanFactory,//管理Bean的生命週期,這個最重要,放最後說

然後回到最頂層抽象類 AbstractApplicationContext ,該抽象類可以說是 ClassPathXmlApplicationContext 繼承結構中程式碼量最多的類,上述的大部分功能也都在該類中實現。該類採用模板方法模式,實現了上述功能的大部分邏輯,然後又抽出許多 protected方法(或 abstract 方法)供子類override 。

各功能的實現列舉如下:

Configable:如setParent/setEnvironment等方法,由AbstractApplicationContext實現 。程式碼示例:

@Override
    public void setParent(ApplicationContext parent) {
        this.parent = parent;
        if (parent != null) {
            Environment parentEnvironment = parent.getEnvironment();
            if (parentEnvironment instanceof ConfigurableEnvironment) {
                getEnvironment().merge((ConfigurableEnvironment) parentEnvironment);
            }
        }
    }

Lifecycle:AbstractApplicationContext擁有一個LifecycleProcessor例項,用於管理自身的生命週期,AbstractApplicationContext的Lifecycle方法如start、stop等由會代理給LifecycleProcessor進行處理,程式碼示例:

@Override
    public void start() {
        getLifecycleProcessor().start();
        publishEvent(new ContextStartedEvent(this));
    }

Closeable:由AbstractApplicationContext實現,用於關閉ApplicationContext銷燬所有beans,此外如果註冊有JVM shutdown hook,同樣要將其移除 。程式碼示例:

@Override
    public void close() {
        synchronized (this.startupShutdownMonitor) {
            doClose();            
            if (this.shutdownHook != null) {
                try {
                    Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
                }catch (IllegalStateException ex) {
                    // ignore - VM is already shutting down
                }
            }
        }
    }

EnvironmentCapable:由AbstractApplicationContext實現,其持有一個ConfigurableEnvironment例項,用來實現EnvironmentCapable介面的getEnvironment方法 。程式碼示例:

@Override
    public ConfigurableEnvironment getEnvironment() {
        if (this.environment == null) {
            this.environment = createEnvironment();
        }
        return this.environment;
    }

MessageSource:AbstractApplicationContext持有一個MessageSource例項,將MessageSource介面的方法代理給該例項來完成 。程式碼示例:

@Override
    public String getMessage(String code, Object args[], String defaultMessage, Locale locale) {
        return getMessageSource().getMessage(code, args, defaultMessage, locale);
    }

ApplicationEventPublisher:由AbstractApplicationContext實現,如果存在父級ApplicationContext,則同樣要將event釋出給父級ApplicationContext。程式碼示例:

@Override
    public void publishEvent(ApplicationEvent event) {
        Assert.notNull(event, "Event must not be null");
        if (logger.isTraceEnabled()) {
            logger.trace("Publishing event in " + getDisplayName() + ": " + event);
        }
        getApplicationEventMulticaster().multicastEvent(event);
        if (this.parent != null) {
            this.parent.publishEvent(event);
        }
    }

ResourcePatternResolver:AbstractApplicationContext持有一個ResourcePatternResolver例項,該介面的方法代理給該例項完成 。程式碼示例:

@Override
    public Resource[] getResources(String locationPattern) throws IOException {
        return this.resourcePatternResolver.getResources(locationPattern);
    }

ListableBeanFactory, HierarchicalBeanFactory: AbstractApplicationContext 間接實現了這兩個介面,然而卻並沒有實現任何BeanFactory的任何功能。AbstractApplicationContext 擁有一個 ConfigurableListableBeanFactory例項,所有BeanFactory的功能都代理給該例項完成。程式碼示例:

@Override
    public Object getBean(String name) throws BeansException {
        assertBeanFactoryActive();
        return getBeanFactory().getBean(name);
    }

而AbstractApplicationContext 的 getBeanFactory() 方法是一個抽象方法,即由子類來提供這個BeanFactory。程式碼示例:

@Override
public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;

在 ClassPathXmlApplicationContext 的繼承體系中,類AbstractRefreshableApplicationContext實現了這個 getBeanFactory()方法。這裡getBeanFactory()方法會建立一個DefaultListableBeanFactory例項作為返回值。

小結

本文以 Spring Framework 的 ApplicationContext 為中心,分析了 ApplicationContext 的機構體系和功能實現。介面 ApplicationContext 繼承了眾多介面,可以滿足應用中“面向介面程式設計”的常用功能需求。抽象類 AbstractApplicationContext 實現了ApplicationContext 介面中簡單不易變動的部分,然後通過“組合”將眾多“容易變動”功能代理給它的一些成員變數來實現,最後再使用模板方法模式讓子類為父類提供一些函式的支援或者設定替換父類的上述成員變數,從而實現了“對擴充套件開放,對修改封閉”的設計原則,為Spring Framework 提供了靈活性大可擴充套件性