理解Spring系列——BeanFactory,Spring IoC的核心擔當

聲明:我已委託「維權騎士」(rightknights.com)爲個人文章進行維權行動。java

導言

經過上一章《理解Spring系列——什麼是控制反轉(Inversion of Control, IoC)》,咱們瞭解到IoC編程模式的本質,經過協議約定來分離when-to-do和what-to-do兩個關注點,實現模塊間的解耦。git

而在Spring Framework中,BeanFactory絕對是Spring IoC的核心擔當:BeanFactory 在Spring中的主要做用,經過抽象Bean實例化的具體過程(體如今BeanDefinition定義),藉助依賴注入(Dependency Inject,DI)的能力,實現基於元數據的業務對象自動裝配,能夠理解成加強版的Guice,以下圖所示。github

Spring中的BeanFactory體系

在Spring Framework中,BeanFactory做爲很是基礎的接口存在,提供了Bean註冊能力(包括Bean查詢、類型判斷、scope判斷等基礎能力);在繼承體系上,能夠分紅BeanFactory實現類ApplicationContext兩條繼承線路。web

二者的關係以下:BeanFactory實現類屬於外觀模式的子系統(SubSystem)承擔着外界提供Bean對象的主要責任,是功能實現的主體;ApplicationContext做爲BeanFactory實現類的外觀系統(Facade System),經過 BeanFactory 提供的接口結合具體的業務場景解析元數據(BeanDefinition )的解析和註冊,並進行Bean對象的初步加載。 另外,ApplicationContext繼承於接口 BeanFactory ,並在BeanFactory的基礎上,提供AoP能力的集成、消息資源的管理、事件發佈機制、以及基於特定場景(Web系統、文件系統)的能力封裝等主要功能。spring

BeanFactory 完整的繼承關係以下圖所示: 編程

BeanFactory 的主要實現類

從圖中能夠看出,BeanFactory 的主要實現類包括StaticListableBeanFactoryDefaultListableBeanFactorySimpleJndiBeanFactory等三個公共類,分別面向靜態場景默認枚舉配置場景JNDI等場景,對應的實現思路也不盡相同。app

  • StaticListableBeanFactory能夠看作是基於Map<String,Object>的簡單封裝,不包括Bean的實例化過程,須要用戶手動註冊後纔可使用,不具有依賴注入能力,是BeanFactory最爲簡單的實現;
  • DefaultListableBeanFactory是Spring BeanFactory的默認實現,是Spring IoC容器中最爲複雜的部分,在後續的章節咱們會進行分析;
  • SimpleJndiBeanFactory則是基於JNDI場景發現對應Bean。

類 DefaultListableBeanFactory

類 DefaultListableBeanFactory 的繼承關係以下圖所示, 從中咱們能夠基本上了解到 類 DefaultListableBeanFactory 的基本功能。post

DefaultListableBeanFactory的接口繼承關係

接口實現上看,類 DefaultListableBeanFactory 主要實現瞭如下基礎的接口:ui

  • AliasRegistry :屬於spring-core模塊(別名能力不限制於Bean Name場景,所以定義在core模塊中),提供String類型別名相關能力,對應的實現類爲 SimpleAliasRegistry ,能夠看作是簡易版的 Map<String,String> 抽象能力,提供別名的增刪改查相關能力;google

  • SingletonBeanRegistry :屬於spring-beans模塊,提供單例bean對象的註冊和查詢能力,能夠看作是簡易版的 Map<String,Object> ;

  • ListableBeanFactory::屬於spring-beans模塊,在 BeanFactory 的基礎上提供更進一步的非精確化查詢能力,支持基於類型( ClassResolvableType )的查詢能力,返回的結果支持beanName 和Map<BeanName,Bean>

  • HierarchicalBeanFactory: 屬於spring-beans模塊,提供多層次的BeanFactory結構,容許多個BeanFactory之間存在繼承關係。例如在 WebApplicationCpontext 的使用場景中, WebApplicationContext 依賴於基於XML配置的 XMLApplicationContext等;

  • AutowireCapableBeanFactory:屬於spring-beans模塊,提供基於bean的自動裝配能力,包括依賴查找(Dependence Lookup)和依賴注入(Dependence Inject)能力;

  • ConfigurableBeanFactory: 屬於spring-beans模塊,提供 DefaultListableBeanFactory 相關數據的讀取和配置接口,同時提供銷燬bean 的能力。

  • ConfigurableListableBeanFactoryAutowireCapableBeanFactory 提供了部分依賴的設置能力,例如,註冊特定類型的依賴默認值( registerResolvableDependency(Class<?> dependencyType, Object autowiredValue) ),判斷某個bean依賴關係是否存在候選集合(boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor)),依賴忽略特定的接口或者類型的依賴注入(ignoreDependencyType(Class<?> type)void ignoreDependencyInterface(Class<?> ifc))。依賴候選集的查詢須要容器提供基於類型查詢對應的bean的能力,所以接口ConfigurableListableBeanFactory繼承了接口ListableBeanFactory,所以,在實現的全部接口中, ConfigurationListableBeanFactory 的繼承關係是最爲複雜的,聚合了不少抽象的能力,是最接近實現類 DefaultListableBeanFactory 的接口,所以在spring 在對外提供BeanFactory預處理接口BeanFactoryPostProcessor的時候,對應的方法簽名是 void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory),而不是~~void postProcessBeanFactory(BeanFactory beanFactory)~~,這樣也能夠避免BeanFactoryPostProcessor#postProcessBeanFactory中傳入的參數是ApplicationContext。

  • 接口BeanDefinitionRegistry 提供了基於beanName的 BeanDefinition 的註冊、刪除和查詢能力。

DefaultListableBeanFactory的類繼承關係

DefaultListableBeanFactory 的類繼承關係,自上到下依次對應的是 Object <- SimpleAliasRegistry <- DefaultSingletonBeanRegistry <- FactoryBeanRegistrySupport <- AbstractBeanFactory <- AbstractAutowireCapableBeanFactory <- DefaultListableBeanFactory 。

從上到下,BeanFactory 關注點變得愈來愈具體,邏輯也變得愈來愈複雜,對應的能力逐漸強大:從最初的別名註冊能力,到bean對象的註冊管理和FactoryBean 對象的管理,再到BeanFactory配置管理,自動裝配能力的實現,最後纔是BeanDefination註冊管理,支持根據BeanDefination進行對象的實例化。

BeanFactory vs FactoryBean

  1. 二者的區別在:前者是工廠類,簡單理解成 beanName和bean對象映射關係的維護者(是個容器),提供根據beanName查詢bean對象的能力;後者是工廠類,描述的是Bean對象實例化的過程,用於生成特定類型的對象。 BeanFactory is a factory, FactoryBean is a bean。
  2. FactoryBean 當你向容器註冊名字爲 factoryBeanName 的 FactoryBean的時候,你向容器註冊的是 名字爲&factoryBeanName的FactoryBean的對象,,經過factoryBeanName獲取到的是 FactoryBean#getObject 返回的對象,該對象不受Spring 容器管理,具體參考What's a FactoryBean?
  3. 當建立Bean的過程當中涉及到多個依賴對象的複雜配置(不是簡單的屬性註冊),或者存在必定的複用性時,能夠經過 FactoryBean 簡化一部分實例過程,減小無關Bean的註冊。例如 AbstractEntityManagerFactoryBean 相關實現。

實例說明

@Configuration
public class FactoryBeanDemo {
    public static final String beanName = "user";

    @Bean(beanName)
    public FactoryBean<User> factoryBean() {
        return new FactoryBean<User>() {
            public User getObject() {
                User user = new User();
                user.setName("mijack");
                return user;
            }

            public Class<?> getObjectType() {
                return User.class;
            }
        };
    }

    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(FactoryBeanDemo.class);
        System.out.println(applicationContext.getBean(beanName) instanceof User);// true
        System.out.println(applicationContext.getBean(beanName) instanceof FactoryBean); // false
        System.out.println(applicationContext.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName) instanceof User);//false
        System.out.println(applicationContext.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName) instanceof FactoryBean);//true
        System.out.println(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, User.class));// [user]
    }
}

複製代碼

ApplicationContext 的類家族

ApplicationContext 繼承的接口上看,接口 ApplicationContext 繼承了接口 ListableBeanFactoryHierarchicalBeanFactoryEnvironmentCapableMessageSourceApplicationEventPublisherResourcePatternResolver,提供IoC容器能力、環境管理、事件發佈機制、事件發佈-響應機制、資源定位加載、i18n的能力。

ApplicationContext 實現的子類上看,ApplicationContext根據不用應用場景分紅不一樣的實現類:

  • 應用在普通場景,仍是web場景?
  • 配置文件是從XML中讀取仍是從Config Class中讀取,或者基於Groovy腳本配置?基於XML讀取的方式資源路徑是感受文件系統來讀取,仍是基於Classpath來讀取?

圖中中藍框部分經過 ApplicationContext -> ConfigurableApplicationContext -> AbstractApplicationContext -> AbstractRefreshableApplicationContext -> AbstractRefreshableConfigApplicationContext -> AbstractRefreshableWebApplicationContext & AbstractXmlApplicationContext 的繼承體系實現了相關功能,可是這樣存在必定問題:不一樣場景下,我文件加載的方式都要從新實現一遍,例如實現XML的配置加載,須要分紅文件系統和Web應用兩種不一樣的實現類,代碼複用度過低。

爲了不上述狀況,進一步提升代碼的利用率,Spring 提出 GenericApplicationContext類繼承體系(紅色框的實現體系): GenericApplicationContext 實現了接口 BeanDefinitionRegistry,將資源註冊過程從核心流程中剝離出來,特定場景下數據加載解析,有子類實現,提供友好的API接口。不一樣於 AbstractRefreshableApplicationContext (維護內部的 BeanFactory ,支持刷新時從新建立 BeanFactory ), GenericApplicationContext 中的 beanFactory 支持從外界導入,爲了不復雜的狀態管理, GenericApplicationContext 默認不支持容器的從新刷新。

相關文章
相關標籤/搜索