Spring bean詳細介紹

banq發表於2019-03-23

簡而言之,Spring bean是Spring框架在執行時管理物件。Spring bean是任何Spring應用程式的基本構建塊。您編寫的大多數應用程式邏輯程式碼都將放在Spring bean中。
Spring bean的管理包括:
  • 建立一個物件
  • 提供依賴項(例如其他bean,配置屬性)
  • 攔截物件方法呼叫以提供額外的框架功能
  • 銷燬一個物件

Spring bean是框架的基本概念。作為Spring的使用者,您應該對這個核心抽象有深刻的理解。

如何定義Spring bean?
如您所知,Spring負責建立bean物件。但首先,您需要告訴框架它應該建立哪些物件。
你是怎麼做到的?
透過提供bean定義

Bean定義告訴Spring框架應該將哪些類用作bean。但那還不是全部。Bean定義就像食譜一樣。它們還描述了bean的屬性。我們將在本文後面討論屬性。但在我們進入之前,讓我們關注bean的定義。
您可以透過三種不同的方式定義Spring bean:

  • 使用構造@Component註釋(或其衍生物)註釋您的類
  • 編寫在自定義Java配置類中使用@Bean註釋的bean工廠方法
  • 在XML配置檔案中宣告bean定義

在現代專案中,您將僅使用元件註釋和bean工廠方法。如果涉及到XML配置,那麼Spring現在主要允許它向後相容。

bean定義方法之間選擇主要取決於對要用作Spring bean的類的原始碼的訪問。

Spring bean為@Component
如果您擁有原始碼,則通常直接在類上使用@Component註釋。

@Component
class MySpringBeanClass {
    //...
}

在執行時,Spring會找到所有使用@Component或其派生類進行註釋的,並將它們用作bean定義。查詢帶註釋的類的過程稱為元件掃描
您可能想知道@Component的衍生物是什麼。
@Conpontent衍生物是Spring構造型註釋,它們本身用@Component註釋。這個事實允許我們用它們代替@Component

@Component衍生列表包括:

  • @Service
  • @Repository
  • @Controller

註釋之間的區別純粹是資訊性的。它們允許您根據通用職責輕鬆對bean進行分類。您可以使用這些註釋將bean類標記為特定應用程式層的成員,Spring框架會將它們全部視為@Components

使用@Bean作為工廠方法
如果某個類屬於某個外部庫而您無法使用@Component進行註釋,您必須在自定義bean的配置類中使用@ Bean註釋建立工廠方法。如果您不想使類依賴於Spring,您也可以將此選項用於您擁有的類。
這是一個帶有單個bean工廠方法的示例配置類:

@Configuration
class MyConfigurationClass {
   
   @Bean
   public NotMyClass notMyClass() {
       return new NotMyClass();
   }
   
}


Spring使用工廠方法在執行時建立實際物件。如您所見,該方法只返回一個類的新例項。如果某個類屬於某個外部庫而您無法使用@Component進行註釋,則使用@Bean建立工廠方法是唯一的選擇。

@Configuration註釋也來自Spring。實際上,它是@Component的衍生物,但具有特殊用途。註釋將類標記為@Bean定義的容器。您可以在單個配置類中編寫多個工廠方法。

Spring bean屬性
此時,您已經知道如何將類標記為Spring bean。下一步是學習如何自定義bean的功能。
無論您選擇哪種bean定義方法,它們都允許描述同一組bean屬性。屬性提供有關Spring應如何建立物件的詳細資訊。
Spring bean屬性列表包括:

  • 名稱
  • 依賴
  • 範圍
  • 初始化模式
  • 初始化回撥
  • 破壞回撥

為了簡化bean定義,Spring為幾乎所有屬性提供了預設值。但是,瞭解如何自定義預設值非常重要。讓我們逐個研究Spring bean屬性。

1.Bean類
建立bean定義時,將其與應用程式中的單個具體類連線。這個類本身是bean的主要屬性。
當Spring查詢依賴項時,class屬性是bean的預設識別符號。這是否意味著您不能為單個類提供多個bean定義?不,這是可能的。但在這種情況下,為避免歧義,您應該使用另一個bean識別符號:一個name名稱。

2. Bean名稱name
Spring bean名稱是Spring用於標識bean的自定義字串。與bean類不同,名稱在整個應用程式中必須是唯一的。您不能定義兩個具有相同名稱的bean,即使它們的型別不同。
幸運的是,您不必為您建立的每個bean設定名稱。Spring在執行時為其內部使用生成名稱。除非您想按名稱識別bean,否則可以安全地使用預設設定。
您需要使用bean名稱的主要情況是為使用@Bean批註定義的同一個類提供了幾個bean。在這種情況下,名稱允許您標識要用作另一個bean的依賴項的特定例項

3. 如何命名Spring bean?
使用@Bean批註的name屬性。這是兩個具有相同型別的bean的示例。

@Configuration
class MyConfigurationClass {
 
   @Bean(name = "myBeanClass")
   MyBeanClass myBeanClass() {
       return new MyBeanClass();
   }
 
   @Bean(name = "anotherMyBeanClass")
   MyBeanClass anotherMyBeanClass() {
       return new MyBeanClass();
   }
 
}

實際上,您不經常定義bean名稱。對於單個類具有多個bean是相當罕見的情況。然而,如果能瞭解命名bean的各種可能性也是不錯的。

4. Bean依賴項
用作bean的物件可以使用其他bean來執行其作業。當Spring建立一個定義某些依賴項的物件時,框架需要首先建立這些依賴項。這些依賴項也可以有自己的依賴項。
物件導向的應用程式中,我們通常使用相關物件巨大圖表。幸運的是,我們不必考慮如何構建此圖。我們不必考慮應該建立物件的順序。Spring為我們做了所有這些。
Spring對您的唯一期望是特定bean的依賴項列表。

5.如何定義bean依賴?
Bean依賴關係定義是一個複雜的主題,值得單獨一篇文章。請考慮以下段落作為該主題的介紹。
當你有一個用@Component標記的並且只有一個建構函式時,Spring使用建構函式引數列表作為必需依賴項列表。預設情況下,框架使用建構函式引數型別來提供適當的物件。

@Component
class BeanWithDependency {
 
   private final MyBeanClass beanClass;
 
   BeanWithDependency(MyBeanClass beanClass) {
       this.beanClass = beanClass;
   }
 
}


過去,我們在建構函式上使用@Autowired註釋。但是,從Spring 4.3開始,如果只有一個建構函式,則不是強制性的。但是,如果bean類定義了多個建構函式,則應使用@Autowired標記一個。這樣Spring知道哪個建構函式包含bean依賴項列表。
出於同樣的原因,bean工廠方法可以定義其依賴關係。Spring使用適當的物件呼叫方法。

@Bean
BeanWithDependency beanWithOptionalDependency(MyBeanClass beanClass) {
   return new BeanWithDependency(beanClass);
}


6. Bean作用域
Spring bean的範圍定義了框架在執行時建立的特定類的例項數。作用域還描述建立新物件的條件
Spring為您的bean提供了幾個作用域。框架的核心有兩個:
  • 單例 - 單個例項
  • 原型 - 多個例項

此外,Spring還附帶了專門用於Web應用程式的bean作用域:
  • 請求
  • 會話
  • 全域性會話
  • 應用級別Application

所有bean的預設作用域是單例。當bean具有單例作用域時,Spring只建立一個例項並在整個應用程式中共享它。單例是無狀態物件的完美選擇。如今,我們應用程式中的絕大多數bean都是無狀態單例。
另一方面,如果物件包含狀態,則應考慮其他作用域。要選擇正確的一個,您應該問自己框架應該將該狀態保留在記憶體中多長時間。但這是另一篇文章。

7. 如何設定作用域?
無論是使用@Component直接註釋還是使用@Bean建立工廠方法,該方法都是相同的。使用@Scope批註及其字串屬性選擇範圍。

@Component
@Scope("prototype")
class MyPrototypeClass {
    //...
}

@Bean
@Scope("prototype")
MyPrototypeClass myPrototypeClass() {
   return new MyPrototypeClass();
}


更重要的是,對於Web作用域,Spring附帶了額外的別名註釋。您可以使用這些註釋代替@Scope
  • @RequestScope
  • @SessionScope
  • @ApplicationScope


Bean初始化模式
當您的應用程式啟動時,Spring會在啟動時會立即建立所有單例bean。此預設行為允許我們快速檢測bean定義中的錯誤。另一方面,立即性eager bean初始化會使應用程式的啟動變慢
幸運的是,您可以將bean的建立延遲到實際需要的時刻。您可以使用@Lazy註釋執行此操作。

@Component
@Lazy
class MyLazyClass {
    //...
}


Bean初始化回撥
一旦Spring根據bean定義建立新例項,您可能希望執行一些物件初始化邏輯。
如果此邏輯不依賴於框架,則可以在物件的建構函式中執行它。但是,為了確保在Spring初始化物件之後執行邏輯(例如,在可選的依賴注入之後),您應該使用初始化回撥。

如何設定bean初始化回撥?
如果使用@Component定義bean ,則有兩個選項:

  • 使bean類實現InitializingBean。介面將強制您實現初始化方法。
  • 編寫自定義初始化方法並使用javax @PostContruct註釋進行標記。

在這兩種情況下,Spring都會為您執行初始化回撥。
用工廠方法定義的bean怎麼樣?
您可以使用@Bean及其名為initMethod的屬性設定初始化回撥。該屬性需要一個具有初始化方法名稱的字串。

@Bean(initMethod = "someInitMethodName")
MySpringBeanClass meBeanClass() {
   return new MySpringBeanClass();
}


有趣的是,用作初始化回撥的方法可以具有私有訪問控制。Spring使用反射機制來呼叫該方法。

Bean銷燬回撥
與初始化回撥類似,您可以定義Spring銷燬bean時應呼叫的方法。Predestroy回撥的使用要少得多,但要注意它們的存在是很好的。

如何設定bean銷燬回撥?
同樣,如果您可以訪問bean類的原始碼,則可以使用以下兩個選項之一:

  • 實現DisposableBean介面。Spring使用其唯一的方法進行銷燬回撥。
  • 編寫自定義方法並使用Javax API中的@PreDestroy註釋它。

對於工廠方法,使用@Bean批註及其destroyMethod屬性。

@Bean(name = "myBeanClass", destroyMethod = "cleanUpMethod")
MySpringBeanClass meBeanClass() {
   return new MySpringBeanClass();
}


Spring如何從bean定義建立物件?
當您啟動Spring應用程式時,框架首先會建立一個名為ApplicationContext的特殊物件。ApplicationContext,也稱為控制反轉(IoC)容器,是框架的核心
ApplicationContext是存在bean物件的容器。
上下文負責檢測和讀取Spring bean定義。一旦ApplicationContext載入了bean定義,它就可以根據提供的bean屬性及其依賴關係開始為應用程式建立bean物件。

 

相關文章