停用某個 Bean 的 Spring 自動組裝
1. 概述
在處理 Spring Boot 專案時,我們可能會遇到需要停用 bean 自動組裝的情況。在本教程中,我們將透過一些用例學習如何在 Spring Boot 應用程式中停用 bean 的自動組裝。
2. 停用自動裝配
首先,讓我們澄清一下,停用 Bean 自動組裝意味著當 Spring Boot 應用程式啟動時,它不會嘗試為特定類別建立 Bean。通常,我們在類別上使用@Component
註解來讓Spring創建它的bean,並使用@Autowired
將該bean注入到聲明的欄位中。
那麼什麼時候會出現這種情況呢?讓我們討論兩個用例。
2.1.在我們的原始碼中
Spring的核心任務之一就是為我們維護bean。它可以創建、維護和銷毀,而無需我們付出任何重大努力。但可能存在這樣的情況:我們有一個類,但不希望在啟動時創建該類的 bean。可能導致這種情況的場景包括循環依賴、延遲載入、多設定檔環境,或管理原型/請求範圍的 bean 以避免不必要的初始化並提高效能。
在變數上使用@Autowired
註解會使 Spring 注入該類型的 bean。這是一個強制性步驟,但在某些情況下我們不想在啟動時自動組裝一些 bean。為了實現這一點,我們可以簡單地使用@Autowired(required = false)
。透過這樣做,我們告訴 Spring 不要自動組裝這個變數——只是忽略它。
2.2.使用第三方函式庫時
讓我們來了解第二個用例。假設我們使用第三方函式庫,並且需要建立一個類別的 bean。但有一個問題! Bean 類別使用內部依賴項,我們不想自動組裝它。此外,我們無法修改他們的程式碼,因為它是第三方函式庫。
讓我們考慮下面的程式碼:
@Component
public class TestBean {
@Autowired
private TestDependency dependency;
...
}
這個類別TestBean
存在於第三方函式庫中,我們想要為它建立一個 bean,但我們不想為TestDependency
建立一個 bean。現在,我們有了用例!
一般來說,第一直覺是使用@Bean
註釋,如下所示:
@Bean
public TestBean testBean() {
return Library.createBean();
}
如果我們使用測試案例來測試這一點:
@Autowired
private ApplicationContext applicationContext;
@Test
void whenTestBeanIsCraetedWithBeanAnnotation_thenItShouldFail() {
TestBean testBean = applicationContext.getBean(TestBean.class);
Assertions.assertNotNull(testBean);
}
它將無法成功運行,並給出異常**No qualifying bean of type 'TestDependency' available: expected at least 1 bean which qualifies as autowire candidate** .
那麼,我們該如何解決這個問題呢?
解決這個問題的方法是使用FactoryBean
類別來建立一個bean。
3. FactoryBean
Factory Bean 是一個充當工廠的 Bean,用於創建其他 Bean 並使用 Spring IOC 容器實例化它們。
此方法在複雜的物件建立場景中非常有用,這使得使用簡單的 XML 或基於註解的配置進行定義變得困難。它通常用於建立代理實例,例如 AOP 代理,其中需要將動態行為新增至物件。
此外,它在整合需要自訂初始化邏輯的第三方函式庫方面發揮關鍵作用,這是我們的第二個用例。
它提供對 bean 實例化的細粒度控制,例如管理智慧型快取或確定建立的 bean 是否應遵循單例範圍。
讓我們看看如何實作FactoryBean
介面。讓我們了解如何以簡單的方式為TestBean
做到這一點:
public class TestBeanFactoryBean implements FactoryBean<TestBean> {
@Override
public TestBean getObject() throws Exception {
return new TestBean();
}
@Override
public Class<?> getObjectType() {
return TestBean.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
因此,在上面的程式碼中,我們提供了在getObject()
方法中建立 bean 的邏輯,並在getObjectType()
中指定了類型 isSingleton()
方法的類別和作用域。我們可以使用這些方法來控制 bean 的建立。
現在,讓我們了解這將如何幫助我們解決問題:
public static <T> FactoryBean<T> createBean(T bean) {
return new FactoryBean<T>() {
public T getObject() throws Exception {
return bean;
}
public Class<?> getObjectType() {
return bean.getClass();
}
public boolean isSingleton() {
return true;
}
};
}
@Bean
static FactoryBean<TestBean> testBean() {
return createBean(new TestBean());
}
在這裡,我們定義瞭如何使用匿名類別建立一個簡單的new TestBean()
。然而,這個邏輯往往來自第三方函式庫。
一個問題可能是為什麼我們將 bean 包裝在FactoryBean
中?為什麼不簡單地回傳new TestBean()
?這個問題的答案是,它會給出一個錯誤,指出沒有找到TestDependency
的 bean。
完成上述變更後,如果我們再次執行 2.2 節中的測試案例,它將成功運行。
4. 結論
在本文中,我們介紹了需要停用 bean 自動組裝的場景。我們也了解如何透過幾個選項來解決這些問題,我們也專門學習了一種使用FactoryBean
介面建立 bean 的新方法。
本文中使用的所有程式碼範例都可以在 GitHub 上找到。