深入理解Spring容器體系結構

前言

在 spring 中,任何實現了 BeanFactory 接口的類都可以視爲容器,它是 IOC 功能實現的核心,用於完成類實例從加載到銷燬的整個生命週期的控制,這些被 spring 所管理的實例統稱爲 bean。

根據抽象層級的不同,容器又分爲 BeanFactory 的直接實現,與基於 BeanFactory 的擴展實現 ApplicationContext,後者在前者的基礎繼承了 ResourceLoaderEnvironmentCapable接口,因而具備從某類運行環境的資源中直接加載 bean 的能力。

image-20220620142154578

ApplicationContext 最常用的兩個實現 ClassPathXmlApplicationContextAnnotationConfigApplicationContext ,前者用於從項目路徑下根據 xml 文件加載 bean,而後者通過掃描類註解完成 bean 的加載。這兩者 ApplicationContext 實際上就對應了我們所熟悉的兩類配置方式,前者就是傳統的 xml 配置,後者則是通過 @Component@Bean 等註解對 bean 進行配置。

本文將基於 spring 源碼 5.2.x 分支,基於 BeanFactoryApplicationContext 兩大接口,介紹 spring 的兩類容器的結構體系。

一、BeanFactory 接口體系

總覽 BeanFactory 體系,按照接口的抽象層次,大體可以分層四層:

  • 第一層:BeanFactory
  • 第二層:HierarchicalBeanFactoryListableBeanFactoryAutowireCapableBeanFactory
  • 第三層:ConfigurableBeanFactory,此外還有一個關聯性較強SingletonBeanRegistry
  • 第四層:ConfigurableListableBeanFactory

image-20220620151809732

1、BeanFactory

BeanFactory 是整個容器體系最頂層的接口,它的內容如下:

public interface BeanFactory {
    String FACTORY_BEAN_PREFIX = "&";
    // 獲取bean相關的方法
    Object getBean(String name) throws BeansException;
    <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;
    Object getBean(String name, Object... args) throws BeansException;
    <T> T getBean(Class<T> requiredType) throws BeansException;
    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
    <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
    <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);

    // 容器 bean 屬性的一些判斷
    boolean containsBean(String name);
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
    boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
    boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

    // 獲取 bean 在容器中的一些屬性
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;
    String[] getAliases(String name);
}

我們可以直接從 BeanFactory 提供的方法看出,BeanFactory 定義了容器的一些基本能力:

  • 容器可以根據名稱、類型、構造函數這三個要素,單獨或兩兩組合的的獲得一個 bean;
  • 容器獲取的 bean 可以是單例多種多例的;
  • 容器中的 bean 可以擁有多個名稱;

2、分層工廠,批量工廠,自動裝配工廠

BeanFactory 存在兩個子接口 HierarchicalBeanFactoryListableBeanFactory,它們進一步的擴展了容器的能力。

分層工廠 HierarchicalBeanFactory

HierarchicalBeanFactory 接口用於表示一個多集嵌套的 BeanFactory

public interface HierarchicalBeanFactory extends BeanFactory {
    // 獲取父工廠
    BeanFactory getParentBeanFactory();
    // 當前工廠是否存在與名稱對應的 bean
    boolean containsLocalBean(String name);
}

批量工廠 ListableBeanFactory

ListableBeanFactory 接口定義了容器根據類型、名稱或類上的註解批量的獲取 bean 或 bean 名稱的能力:

public interface ListableBeanFactory extends BeanFactory {
    // 容器中是否存在 bean
    boolean containsBeanDefinition(String beanName);
    // 容器中定義了多少 bean
    int getBeanDefinitionCount();
    // 獲取容器中所有定義了的 bean 名稱
    String[] getBeanDefinitionNames();
    
    // 根據類型批量獲取 bean
    String[] getBeanNamesForType(ResolvableType type);
    String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit);
    String[] getBeanNamesForType(@Nullable Class<?> type);
    String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit);
    <T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException;
    <T> Map<String, T> getBeansOfType(@Nullable Class<T> type, boolean includeNonSingletons, boolean allowEagerInit) throws BeansException;
    
    // 根據類上的註解獲取 bean
    String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType);
    Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException;
    <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType) throws NoSuchBeanDefinitionException;
}

根據註釋,當一個類同時實現了 HierarchicalBeanFactoryListableBeanFactory 接口時,ListableBeanFactory 中的方法是不會考慮到父工廠的,也就是說,spring 中的 ListableBeanFactory 接口表示的能力只針對當前實現它的類。

自動裝配工廠 AutowireCapableBeanFactory

AutowireCapableBeanFactory 如同他的名稱一樣,用於爲容器關聯的 bean 提供自動裝配功能:

public interface AutowireCapableBeanFactory extends BeanFactory {
    
    // 自動裝配方式
	int AUTOWIRE_NO = 0; // 不自動裝配
	int AUTOWIRE_BY_NAME = 1; // 根據bean名稱自動裝配
	int AUTOWIRE_BY_TYPE = 2; // 根據bean類型自動裝配
	int AUTOWIRE_CONSTRUCTOR = 3; // 根據bean的構造方法自動裝配
	int AUTOWIRE_AUTODETECT = 4; // 根據反射信息自動選擇合適的方式自動裝配,spring3 以後不再推薦該方式
	String ORIGINAL_INSTANCE_SUFFIX = ".ORIGINAL";
    
    // bean的創建與裝配相關的方法
	<T> T createBean(Class<T> beanClass) throws BeansException;
	void autowireBean(Object existingBean) throws BeansException;
	Object configureBean(Object existingBean, String beanName) throws BeansException;
    
    // bean 聲明週期相關的方法
	Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
	Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
	void autowireBeanProperties(Object existingBean, int autowireMode, boolean dependencyCheck) throws BeansException;
	void applyBeanPropertyValues(Object existingBean, String beanName) throws BeansException;
	Object initializeBean(Object existingBean, String beanName) throws BeansException;
	Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException;
	Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException;
	void destroyBean(Object existingBean);
    
    // 獲取 bean 依賴的相關方法
	<T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType) throws BeansException;
	Object resolveBeanByName(String name, DependencyDescriptor descriptor) throws BeansException;
	Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException;
	Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException;
    
}

比較值得注意的是,通過 AutowireCapableBeanFactory 定義的 API 不難看出,只要能獲得對應的實例,我們是可以手動的對非 spring 託管的 bean 進行依賴注入的。

3、分層配置工廠

BeanFactory 的三級接口爲 ConfigurableBeanFactory,它實現了 HierarchicalBeanFactorySingletonBeanRegistry接口。

從字面上理解,它是一個可配置的 BeanFactory,它不僅支持 BeanFactory 分層,還支持以單例的方式操作 bean。它是整個 BeanFactory 體系中最重要的一環,通過這個接口,spring 通過該接口規定了一個 BeanFactory 應該具備以及可以從中獲取哪些可配置的組件與參數。

這裏我們先了解一下 SingletonBeanRegistry 接口,這個接口定義了容器根據名稱註冊或獲取 bean 單例的能力:

public interface SingletonBeanRegistry {
    void registerSingleton(String beanName, Object singletonObject);
    Object getSingleton(String beanName);
    boolean containsSingleton(String beanName);
    String[] getSingletonNames();
    int getSingletonCount();
    Object getSingletonMutex();
}

然後回到 ConfigurableBeanFactory ,它在 HierarchicalBeanFactory 的基礎上補充了大量的方法:

public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {
	String SCOPE_SINGLETON = "singleton"; // 單例
	String SCOPE_PROTOTYPE = "prototype"; // 多例

	// 配置父工廠
	void setParentBeanFactory(BeanFactory parentBeanFactory) throws IllegalStateException;
	
	// 配置類加載器
	void setBeanClassLoader(@Nullable ClassLoader beanClassLoader);
	ClassLoader getBeanClassLoader();
	void setTempClassLoader(@Nullable ClassLoader tempClassLoader);
	ClassLoader getTempClassLoader();
	
	// 配置bean元信息緩存
	void setCacheBeanMetadata(boolean cacheBeanMetadata);
	boolean isCacheBeanMetadata();
	
	// 配置bean配置的表達式解析器,用於提供@Value值註冊等功能
	void setBeanExpressionResolver(@Nullable BeanExpressionResolver resolver);
	BeanExpressionResolver getBeanExpressionResolver();
	
	// 配置類型轉換器
	void setConversionService(@Nullable ConversionService conversionService);
	ConversionService getConversionService();
	void setTypeConverter(TypeConverter typeConverter);
	TypeConverter getTypeConverter();
	
	// 配置屬性註冊表
	void addPropertyEditorRegistrar(PropertyEditorRegistrar registrar);
	void registerCustomEditor(Class<?> requiredType, Class<? extends PropertyEditor> propertyEditorClass);
	void copyRegisteredEditorsTo(PropertyEditorRegistry registry);
	
	// 配置字符串解析器,用於提供解析xml中的bean屬性的表達式等功能
	void addEmbeddedValueResolver(StringValueResolver valueResolver);
	boolean hasEmbeddedValueResolver();
	String resolveEmbeddedValue(String value);
	
	// 配置bean的後置處理器BeanPostProcessor
	void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);
	int getBeanPostProcessorCount();

	// 配置bean的作用域,接口中已經默認提供了單例或多例的scopeName
	void registerScope(String scopeName, Scope scope);
	String[] getRegisteredScopeNames();
	Scope getRegisteredScope(String scopeName);

	// 配置訪問控制
	AccessControlContext getAccessControlContext();

	// 從其他的工廠複製配置
	void copyConfigurationFrom(ConfigurableBeanFactory otherFactory);

	// 給指定的bean註冊別名
	void registerAlias(String beanName, String alias) throws BeanDefinitionStoreException;
	void resolveAliases(StringValueResolver valueResolver);
	
	// 合併bean的定義信息
	BeanDefinition getMergedBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

	// 是否是工廠bean
	boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException;
	
	// 設置bean的創建狀態,管理bean的依賴與被依賴關係,用於處理循環依賴等問題
	void setCurrentlyInCreation(String beanName, boolean inCreation);
	boolean isCurrentlyInCreation(String beanName);
	void registerDependentBean(String beanName, String dependentBeanName);
	String[] getDependentBeans(String beanName);
	String[] getDependenciesForBean(String beanName);

	// bean的銷燬相關方法
	void destroyBean(String beanName, Object beanInstance);
	void destroyScopedBean(String beanName);
	void destroySingletons();
}

這個接口定義了非常多的 API,按照用途來說,這些 API 大概分爲三類:

  • bean 的管理方法:包括 bean 依賴狀態與生命週期的獲取,bean 的銷燬,bean 作用域域、定義信息與別名的操作;
  • bean 創建過程中使用組件的配置:包括字符串解析器,類加載器,類型轉換器,屬性註冊表,bean 的後置處理器等組件的配置;
  • 工廠本身狀態的一些操作:包括父工程配置,工廠間依賴的拷貝,以及訪問控制等。

4、批量分層配置工廠

ConfigurableListableBeanFactoryBeanFactory 體系的第四級接口,也是最後一級接口。它繼承了 ConfigurableBeanFactoryListableBeanFactoryAutowireCapableBeanFactory 接口,因此它具備到目前爲止 BeanFactory 前三級接口定義的全部能力。

它表示了一個可以配置的,允許按單例或多例操作 bean,支持自動裝配 bean,並且可以根據 bean 的名稱、類型或者類上註解批量獲取 bean 的超級 bean 工廠。

image-20220620150717261

它在上述功能的基礎上,又針對各接口提供的功能定義了一些新的補充方法:

public interface ConfigurableListableBeanFactory extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory {
    // 自動裝配相關配置
    void ignoreDependencyType(Class<?> type);
    void ignoreDependencyInterface(Class<?> ifc);
    void registerResolvableDependency(Class<?> dependencyType, @Nullable Object autowiredValue);
    boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor) throws NoSuchBeanDefinitionException;
    
    // 獲取bean的定義信息
    BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
    
    // 獲取已經定義的bean名稱的迭代器
    Iterator<String> getBeanNamesIterator();
    // 清除bean元信息緩存
    void clearMetadataCache();
    
    // 凍結配置,凍結後工廠的配置不允許進一步修改
    void freezeConfiguration();
    boolean isConfigurationFrozen();
    
    // 實例化所有未實例化的單例bean
    void preInstantiateSingletons() throws BeansException;
}

二、ApplicationContext 接口體系

嚴格來說,ApplicationContextBeanFactory 的子類,或者說,BeanFactory 是其組成的一部分。但是由於其附加了很多 BeanFactory 所不具備的功能,因此一般將其與 BeanFactory 體系分開看待。

ApplicationContext 有 web 環境上下文與非 web 環境上下文的兩個實現體系,單純按接口層次分爲三層:

  • 第一層:ApplicationContext
  • 第二層:WebApplicationContextConfigurableApplicationContext
  • 第三層:ConfigurableApplicationContext

image-20220620173854597

1、ApplicationContext

ApplicationContext 接口是基於 BeanFactory 的進一步實現,它同時實現了 EnvironmentCapableListableBeanFactoryHierarchicalBeanFactoryMessageSourceApplicationEventPublisher 以及 ResourcePatternResolver 接口。相較 BeanFactory ,它的功能要更加強大。

image-20220620142154578

ApplicationContext 繼承的各個接口分別對應它提供各項功能:

  • HierarchicalBeanFactoryListableBeanFactory:提供像 BeanFactory 一樣操作 bean 的功能;
  • ApplicationEventPublisher:提供向監聽器發佈事件的能力;
  • ResourcePatternResolverEnvironmentCapable:提供選擇性的某個特定環境的文件資源中加載配置的能力;
  • MessageSource:提供解析消息並支持國際化配置的能力;

結合它提供的功能和它的名稱,我們可以大概瞭解,與 BeanFactory 專門用於操作 bean 不同,ApplicationContext 用於提供 spring 程序在某個特定環境運行時所具備的全部信息的“上下文”對象,它之於 BeanFactory ,就像帶各種功能的超級保溫杯之於普通的水杯。

它定義的方法如下:

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
    // 獲取上下文id
    String getId();
    // 獲取對應應用程序名稱
    String getApplicationName();
    // 獲取上下文的展示名稱
    String getDisplayName();
    // 獲取容器被啓動的時間
    long getStartupDate();
    // 獲取父級上下文
    ApplicationContext getParent();
    // 獲取自動裝配bean工廠
    AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}

這裏可以看到,雖然 ApplicationContext 沒繼承 AutowireCapableBeanFactory 接口,但是他依然可以通過方法獲取到對應的裝配工廠。

2、web 應用上下文與可配置上下文

WebApplicationContext

WebApplicationContext 是 web 環境的上下文,該上下文幾乎沒有可配置項,主要用於配置 Servlet 上下文:

public interface WebApplicationContext extends ApplicationContext {
    String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
    
    // 作用域
    String SCOPE_REQUEST = "request";
    String SCOPE_SESSION = "session";
    String SCOPE_APPLICATION = "application";
    
    // 固定的bean名稱
    String SERVLET_CONTEXT_BEAN_NAME = "servletContext";
    String CONTEXT_PARAMETERS_BEAN_NAME = "contextParameters";
    String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes";
    
    // 獲取ServletContext
    ServletContext getServletContext();

}

ConfigurableApplicationContext

ConfigurableApplicationContext 表示一個可以配置的上下文容器,與 WebApplicationContext 不同,它提供了一些參數和屬性的配置方法:

public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
    
    String CONFIG_LOCATION_DELIMITERS = ",; \t\n";
    String CONVERSION_SERVICE_BEAN_NAME = "conversionService";
    String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver";
    String ENVIRONMENT_BEAN_NAME = "environment";
    String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";
    String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";
    String SHUTDOWN_HOOK_THREAD_NAME = "SpringContextShutdownHook";
    
    // 配置上下文的id
    void setId(String id);
    // 配置上下文父容器
    void setParent(@Nullable ApplicationContext parent);
    
    // 配置上下文允許環境
    void setEnvironment(ConfigurableEnvironment environment);
    @Override
    ConfigurableEnvironment getEnvironment();
    
    // 獲取bean後置處理器
    void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);
    
    // 添加一個應用監聽器,用於監聽ApplicationEventPublisher發佈的事件
    void addApplicationListener(ApplicationListener<?> listener);
    
    // 配置類加載器
    void setClassLoader(ClassLoader classLoader);
    
    // 配置資源協議處理器
    void addProtocolResolver(ProtocolResolver resolver);
    
    // 刷新配置
    void refresh() throws BeansException, IllegalStateException;
    
    // 關閉此上下文容器時的回調函數
    void registerShutdownHook();
    
    // 關閉上下文容器,並釋放資源
    void close();
    
    // 當前容器是否已經調用過refresh(),並且尚未關閉
    boolean isActive();
    
    // 獲取bean工廠
    ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;

}

它有一個通用可配置上下文的實現類:GenericApplicationContext,在非 web 環境中,該實現類的兩個子類是最經常用到的:

  • GenericXmlApplicationContext:基於 xml 配置文件配置的上下文;
  • AnnotationConfigApplicationContext:基於註解配置的上下文;

3、可配置的web應用上下文

ConfigurableApplicationContext 接口同時繼承了 WebApplicationContextConfigurableApplicationContext,代表了一個可以配置的 web 上下文容器:

public interface ConfigurableWebApplicationContext extends WebApplicationContext, ConfigurableApplicationContext {

	String APPLICATION_CONTEXT_ID_PREFIX = WebApplicationContext.class.getName() + 
	String SERVLET_CONFIG_BEAN_NAME = "servletConfig";

	// 配置Servlet容器
	void setServletContext(@Nullable ServletContext servletContext);
	void setServletConfig(@Nullable ServletConfig servletConfig);
	@Nullable
	ServletConfig getServletConfig();

    // 設置命名空間
	void setNamespace(@Nullable String namespace);
	@Nullable
	String getNamespace();
	
	// 設置配置文件的路徑,比如WEB-INF
	void setConfigLocation(String configLocation);
	void setConfigLocations(String... configLocations);
	@Nullable
	String[] getConfigLocations();

}

一般 web 環境下實例化的上下文都爲該接口的實例。

三、總結

在 spring 中,容器分爲兩大類:BeanFactoryApplicationContext

BeanFactory

其中,BeanFactory 是純粹的用於管理 bean 對象生命週期的容器,它的接口體系分爲四層:

  1. BeanFactory 接口本身,是容器的最高層抽象;

  2. HierarchicalBeanFactory :分層工廠,表示一個存在層級關係的容器;

    ListableBeanFactory:批量工廠,表示一個允許根據名稱、類型或類註解等屬性批量的操作 bean 的容器;

    AutowireCapableBeanFactory:自動裝配工廠,表示一個可以關聯需要自動裝配的 bean 的容器;

  3. ConfigurableBeanFactory:分層配置工廠 ,是 HierarchicalBeanFactorySingletonBeanRegistry 接口的組合,表示一個分層的、可以以單例模式操作 bean,並且允許調整配置的容器;

  4. ConfigurableListableBeanFactory:可配置的批量工廠,是ConfigurableBeanFactoryAutowireCapableBeanFactory 接口的組合,具備 BeanFactory 體系中的全部能力。

ApplicationContext

ApplicationContext 是基於 BeanFactory 的擴展,它實現了其他的接口,因此具有一些 BeanFactory 不具備的功能:

  • ApplicationEventPublisher:提供向監聽器發佈事件的功能;
  • ResourcePatternResolverEnvironmentCapable:提供選擇性的某個特定環境的文件資源中加載配置的功能;
  • MessageSource:提供解析消息並支持國際化配置的功能;

從層次來說,ApplicationContext 主要分爲三層:

  1. ApplicationContext 接口本身,是基於 BeanFactory 接口的擴展,是整個應用上下文體系的最頂層接口;

  2. WebApplicationContext:web 應用上下文,用於承載 ServletContext

    ConfigurableApplicationContext:用於非 web 環境下的可配置應用上下文;

  3. ConfigurableApplicationContext:可配置的 web 應用上下文,同時繼承了 WebApplicationContextConfigurableApplicationContext 接口,代表了一個可以配置的 web 上下文容器。

    在一般的 web 環境中啓動的都是該上下文的實例。

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