Spring 容器型別

最後更新: 2023-12-14 04:20:44 +0800 +0800
原文以英文撰寫。您正在閱讀AI翻譯版本。

Spring 的容器 API 有三個不同層級:Bean 中繼資料、從該中繼資料建立物件的工廠,以及協調工廠與應用程式服務的應用程式上下文。保持這些層級分離,可以更容易理解 Spring 原始碼與擴充點。

Bean 定義與登錄 #

BeanDefinition 是單一 Bean 的可變中繼資料。它記錄 Bean 類別或類別名稱、範圍、建構函式引數、屬性值、限定詞、工廠方法、生命週期方法、角色、來源位置與明確相依性。父子中繼資料關係獨立於 Java 繼承。

常見實作服務於不同的註冊路徑:

  • RootBeanDefinition 表示 Bean 工廠使用的合併定義。
  • ChildBeanDefinition 從具名父定義繼承中繼資料。
  • GenericBeanDefinition 在合併前可表達獨立或衍生自父項的中繼資料。
  • AnnotatedGenericBeanDefinition 暴露已註冊類別的註解中繼資料。
  • ScannedGenericBeanDefinition 暴露類別路徑掃描期間讀取的中繼資料,而不先載入元件類別。

BeanDefinitionRegistry 依 Bean 名稱儲存定義。其核心作業是註冊、移除與查詢定義;DefaultListableBeanFactory 與 GenericApplicationContext 是重要實作。

AnnotatedBeanDefinitionReader 註冊明確提供的元件類別:

java
var context = new GenericApplicationContext();
var reader = new AnnotatedBeanDefinitionReader(context);
reader.register(OrderService.class);
context.refresh();

ClassPathBeanDefinitionScanner 搜尋套件中的候選元件並註冊其定義。兩種機制都會套用註解範圍、命名、限定詞、條件與 BeanDefinitionCustomizer 回呼。客製化器可在註冊期間進行針對性的中繼資料變更,而不必實作登錄後處理器。

BeanFactory、FactoryBean 與 ObjectFactory #

BeanFactory 是執行階段登錄與相依性解析 API。它定位定義、建立 Bean、解析協作者、管理單例識別,並套用生命週期處理器。ListableBeanFactory 加入列舉,HierarchicalBeanFactory 加入父項查找,而 ConfigurableListableBeanFactory 將容器設定暴露給框架基礎設施。應用程式程式碼應依賴其網域協作者,而不是把 getBean() 當作服務定位器呼叫。

三個名稱相似的型別具有不同責任:

  • BeanFactory 是容器。
  • FactoryBean<T> 是建立另一個物件的 Bean。查找其名稱會回傳產品;在名稱前加上 & 會回傳工廠本身。getObjectType() 與 isSingleton() 描述產品。
  • ObjectFactory<T> 是具有 getObject() 的最小回呼。Spring 將它用於延後擷取與內部建立回呼。ObjectProvider<T> 以選擇性、有順序與串流式存取擴充模型。

應用程式上下文階層 #

ApplicationContext 擴充 ListableBeanFactory、HierarchicalBeanFactory、MessageSource、ApplicationEventPublisher、ResourcePatternResolver 及相關環境能力。ConfigurableApplicationContext 加入 refresh()、close()、環境設定與存取可設定工廠等生命週期作業。

AbstractApplicationContext 實作重新整理演算法。專用基底類別決定定義如何抵達工廠:

  • GenericApplicationContext 擁有一個內部 DefaultListableBeanFactory。可以在一次 refresh() 呼叫前,透過其登錄 API 註冊定義。
  • AnnotationConfigApplicationContext 將一般上下文與 AnnotatedBeanDefinitionReader 及 ClassPathBeanDefinitionScanner 結合。其建構函式可以註冊類別或掃描套件,然後重新整理。
  • 支援 Servlet 的上下文加入 Web 範圍與 Servlet 資源,但保留相同的核心工廠契約。

部分較舊的上下文實作會在重新整理期間重新建立 Bean 工廠,而 GenericApplicationContext 不支援重複的重新整理嘗試。框架擴充必須遵循具體上下文的生命週期,而不是假設每個上下文都能重新整理超過一次。

重新整理與產生的定義 #

註解註冊最初會為提供的類別建立定義。重新整理期間,ConfigurationClassPostProcessor 會剖析 @Configuration、元件掃描、匯入與 @Bean 方法,然後在一般 Bean 實例化前註冊額外定義。登錄後處理器可以在相同階段產生更多定義。Spring 的 AOT 處理可以預先產生註冊程式碼,但產生的定義仍會餵入相同的 Bean 工廠模型。

ApplicationStartup 在不改變生命週期語意的情況下檢測啟動。DefaultApplicationStartup 是低負擔的無操作實作,BufferingApplicationStartup 保留有界的步驟資料,而 FlightRecorderApplicationStartup 發出 Java Flight Recorder 事件。StartupStep 具有名稱、標籤與明確結束;自訂基礎設施應讓標籤保持低成本,因為啟動檢測會在關鍵路徑上執行。

選擇擴充點 #

請使用符合需求的最窄層級:

  1. 使用 BeanDefinitionCustomizer 在註冊時客製化定義。
  2. 使用 BeanDefinitionRegistryPostProcessor 或 BeanFactoryPostProcessor 加入或轉換中繼資料。
  3. 使用 BeanPostProcessor 攔截實例。
  4. 使用 FactoryBean 建立產生物件的 Bean。
  5. 在 GenericApplicationContext 或應用程式上下文子型別上建立完整協調的容器。

主要參考資料 #

評論

在 GitHub 上閱讀或評論(發表評論需要登入)