1. 程式人生 > >【String註解驅動開發】如何按照條件向Spring容器中註冊bean?這次我懂了!!

【String註解驅動開發】如何按照條件向Spring容器中註冊bean?這次我懂了!!

## 寫在前面 > 當bean是單例項,並且沒有設定懶載入時,Spring容器啟動時,就會例項化bean,並將bean註冊到IOC容器中,以後每次從IOC容器中獲取bean時,直接返回IOC容器中的bean,不再建立新的bean。 > > 如果bean是單例項,並且使用@Lazy註解設定了懶載入,則Spring容器啟動時,不會例項化bean,也不會將bean註冊到IOC容器中,只有第一次獲取bean的時候,才會例項化bean,並且將bean註冊到IOC容器中。 > > 如果bean是多例項,則Spring容器啟動時,不會例項化bean,也不會將bean註冊到IOC容器中,以後每次從IOC容器中獲取bean時,都會建立一個新的bean返回。 > > Spring支援按照條件向IOC容器中註冊bean,滿足條件的bean就會被註冊到IOC容器中,不滿足條件的bean就不會被註冊到IOC容器中。接下來,我們就一起來探討Spring中如何實現按照條件向IOC容器中註冊bean。 > > 專案工程原始碼已經提交到GitHub:[https://github.com/sunshinelyz/spring-annotation](https://github.com/sunshinelyz/spring-annotation) ## @Conditional註解概述 @Conditional註解可以按照一定的條件進行判斷,滿足條件向容器中註冊bean,不滿足條件就不向容器中註冊bean。 @Conditional註解是由 SpringFramework 提供的一個註解,位於 org.springframework.context.annotation 包內,定義如下。 ```java package org.springframework.context.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Conditional { Class[] value(); } ``` 從@Conditional註解的原始碼來看,@Conditional註解可以新增到類上,也可以新增到方法上。在@Conditional註解中,存在一個Condition型別或者其子型別的Class物件陣列,Condition是個啥?我們點進去看一下。 ```java package org.springframework.context.annotation; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.core.type.AnnotatedTypeMetadata; @FunctionalInterface public interface Condition { boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata); } ``` 可以看到,Condition是一個函式式介面,對於函式式介面不瞭解的同學可以參見【Java8新特性】中的《[【Java8新特性】還沒搞懂函式式介面?趕快過來看看吧!](https://mp.weixin.qq.com/s?__biz=Mzg3MzE1NTIzNA==&mid=2247484537&idx=1&sn=e83c8394f8e4ae5408edea37590ce68c&chksm=cee51bb4f99292a2529ee9eccbd6190df8e228b91383519bb0aacf7f9b16375f0e4a3c5143c8&token=2141222822&lang=zh_CN#rd)》一文。也可以直接檢視《[Java8新特性專欄](https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&__biz=Mzg3MzE1NTIzNA==&scene=1&album_id=1325066823947321344&uin=MjY0ODI3NDMxNQ%3D%3D&key=6898a2b07ab8315b346e49cb946636ac30bf791060f59e1b3f9f4ea45fb4da4877bfadf96f172ddd5c6b08a41f048552cb5f0bd0ce35428c3b965b4ad02581553b0146795ea47d06c637b6ac15c1aa2f&devicetype=Windows+10+x64&version=62090070&lang=zh_CN&ascene=1&pass_ticket=qJSd3kgjDozsrmjeER7cQ2NthBP7CDbXMWtwnybrvKPZeqAFnyLdEnCu4KuRgr28)》來系統學習Java8的新特性。 所以,我們使用@Conditional註解時,需要一個類實現Spring提供的Condition介面,它會匹配@Conditional所符合的方法,然後我們可以使用我們在@Conditional註解中定義的類來檢查。 **@Conditional註解的使用場景如下所示。** - **可以作為類級別的註解直接或者間接的與@Component相關聯,包括@Configuration類;** - **可以作為元註解,用於自動編寫構造性註解;** - **作為方法級別的註解,作用在任何@Bean方法上。** ## 向Spring容器註冊bean ### 不帶條件註冊bean 我們在PersonConfig2類中新增person01()方法和person02()方法,併為兩個方法新增@Bean註解,如下所示。 ```java @Bean("binghe001") public Person person01(){ return new Person("binghe001", 18); } @Bean("binghe002") public Person person02(){ return new Person("binghe002", 20); } ``` 那麼,這兩個bean預設是否會被註冊到Spring容器中呢,我們新建一個測試用例來測試一下。在SpringBeanTest類中新建testAnnotationConfig6()方法,如下所示。 ```java @Test public void testAnnotationConfig6(){ ApplicationContext context = new AnnotationConfigApplicationContext(PersonConfig2.class); String[] names = context.getBeanNamesForType(Person.class); Arrays.stream(names).forEach(System.out::println); } ``` 我們執行testAnnotationConfig6()方法,輸出的結果資訊如下所示。 ```bash person binghe001 binghe002 ``` 從輸出結果可以看出,同時輸出了binghe001和binghe002。說明預設情況下,Spring容器會將單例項並且非懶載入的bean註冊到IOC容器中。 接下來,我們再輸出bean的名稱和bean例項物件資訊,此時我們在testAnnotationConfig6()方法中新增相應的程式碼片段,如下所示。 ```java @Test public void testAnnotationConfig6(){ ApplicationContext context = new AnnotationConfigApplicationContext(PersonConfig2.class); String[] names = context.getBeanNamesForType(Person.class); Arrays.stream(names).forEach(System.out::println); Map