天天看點

深入了解Spring容器體系結構「建議收藏」

大家好,又見面了,我是你們的朋友全棧君。

前言

在 spring 中,任何實作了

BeanFactory

接口的類都可以視為容器,它是

IOC

功能實作的核心,用于完成類執行個體從加載到銷毀的整個生命周期的控制,這些被 spring 所管理的執行個體統稱為 bean。

根據抽象層級的不同,容器又分為

BeanFactory

的直接實作,與基于

BeanFactory

的擴充實作

ApplicationContext

,後者在前者的基礎繼承了

ResourceLoader

EnvironmentCapable

接口,因而具備從某類運作環境的資源中直接加載 bean 的能力。

深入了解Spring容器體系結構「建議收藏」

ApplicationContext

最常用的兩個實作

ClassPathXmlApplicationContext

AnnotationConfigApplicationContext

,前者用于從項目路徑下根據

xml

檔案加載 bean,而後者通過掃描類注解完成 bean 的加載。這兩者

ApplicationContext

實際上就對應了我們所熟悉的兩類配置方式,前者就是傳統的 xml 配置,後者則是通過

@Component

@Bean

等注解對 bean 進行配置。

本文将基于 spring 源碼

5.2.x

分支,基于

BeanFactory

ApplicationContext

兩大接口,介紹 spring 的兩類容器的結構體系。

一、BeanFactory 接口體系

總覽

BeanFactory

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

  • 第一層:

    BeanFactory

  • 第二層:

    HierarchicalBeanFactory

    ListableBeanFactory

    AutowireCapableBeanFactory

  • 第三層:

    ConfigurableBeanFactory

    ,此外還有一個關聯性較強

    SingletonBeanRegistry

  • 第四層:

    ConfigurableListableBeanFactory

深入了解Spring容器體系結構「建議收藏」

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

存在兩個子接口

HierarchicalBeanFactory

ListableBeanFactory

,它們進一步的擴充了容器的能力。

分層工廠 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;
}           

複制

根據注釋,當一個類同時實作了

HierarchicalBeanFactory

ListableBeanFactory

接口時,

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

,它實作了

HierarchicalBeanFactory

SingletonBeanRegistry

接口。

從字面上了解,它是一個可配置的

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、批量分層配置工廠

ConfigurableListableBeanFactory

BeanFactory

體系的第四級接口,也是最後一級接口。它繼承了

ConfigurableBeanFactory

ListableBeanFactory

AutowireCapableBeanFactory

接口,是以它具備到目前為止

BeanFactory

前三級接口定義的全部能力。

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

深入了解Spring容器體系結構「建議收藏」

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

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 接口體系

嚴格來說,

ApplicationContext

BeanFactory

的子類,或者說,

BeanFactory

是其組成的一部分。但是由于其附加了很多

BeanFactory

所不具備的功能,是以一般将其與

BeanFactory

體系分開看待。

ApplicationContext

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

  • 第一層:

    ApplicationContext

  • 第二層:

    WebApplicationContext

    ConfigurableApplicationContext

  • 第三層:

    ConfigurableApplicationContext

深入了解Spring容器體系結構「建議收藏」

1、ApplicationContext

ApplicationContext

接口是基于

BeanFactory

的進一步實作,它同時實作了

EnvironmentCapable

ListableBeanFactory

HierarchicalBeanFactory

MessageSource

ApplicationEventPublisher

以及

ResourcePatternResolver

接口。相較

BeanFactory

,它的功能要更加強大。

深入了解Spring容器體系結構「建議收藏」

ApplicationContext

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

  • HierarchicalBeanFactory

    ListableBeanFactory

    :提供像

    BeanFactory

    一樣操作 bean 的功能;
  • ApplicationEventPublisher

    :提供向監聽器釋出事件的能力;
  • ResourcePatternResolver

    EnvironmentCapable

    :提供選擇性的某個特定環境的檔案資源中加載配置的能力;
  • 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

接口同時繼承了

WebApplicationContext

ConfigurableApplicationContext

,代表了一個可以配置的 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 中,容器分為兩大類:

BeanFactory

ApplicationContext

BeanFactory

其中,

BeanFactory

是純粹的用于管理 bean 對象生命周期的容器,它的接口體系分為四層:

  1. BeanFactory

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

    :分層工廠,表示一個存在層級關系的容器;

    ListableBeanFactory

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

    AutowireCapableBeanFactory

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

    :分層配置工廠 ,是

    HierarchicalBeanFactory

    SingletonBeanRegistry

    接口的組合,表示一個分層的、可以以單例模式操作 bean,并且允許調整配置的容器;
  4. ConfigurableListableBeanFactory

    :可配置的批量工廠,是

    ConfigurableBeanFactory

    AutowireCapableBeanFactory

    接口的組合,具備

    BeanFactory

    體系中的全部能力。

ApplicationContext

ApplicationContext

是基于

BeanFactory

的擴充,它實作了其他的接口,是以具有一些

BeanFactory

不具備的功能:

  • ApplicationEventPublisher

    :提供向監聽器釋出事件的功能;
  • ResourcePatternResolver

    EnvironmentCapable

    :提供選擇性的某個特定環境的檔案資源中加載配置的功能;
  • MessageSource

    :提供解析消息并支援國際化配置的功能;

從層次來說,

ApplicationContext

主要分為三層:

  1. ApplicationContext

    接口本身,是基于

    BeanFactory

    接口的擴充,是整個應用上下文體系的最頂層接口;
  2. WebApplicationContext

    :web 應用上下文,用于承載

    ServletContext

    ConfigurableApplicationContext

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

    :可配置的 web 應用上下文,同時繼承了

    WebApplicationContext

    ConfigurableApplicationContext

    接口,代表了一個可以配置的 web 上下文容器。

    在一般的 web 環境中啟動的都是該上下文的執行個體。

釋出者:全棧程式員棧長,轉載請注明出處:https://javaforall.cn/170762.html原文連結:https://javaforall.cn