在前面的文章中,咱們知道能夠經過多種方式向Spring容器中註冊bean。能夠使用@Configuration結合@Bean向Spring容器中註冊bean;能夠按照條件向Spring容器中註冊bean;能夠使用@Import向容器中快速導入bean對象;能夠在@Import中使用ImportBeanDefinitionRegistrar向容器中註冊bean。java
項目工程源碼已經提交到GitHub:https://github.com/sunshinelyz/spring-annotationgit
通常狀況下,Spring經過反射機制利用bean的class屬性指定實現類來實例化bean 。在某些狀況下,實例化bean過程比較複雜,若是按照傳統的方式,則須要在
FactoryBean接口對於Spring框架來講佔有重要的地位,Spring 自身就提供了70多個FactoryBean的實現。它們隱藏了實例化一些複雜bean的細節,給上層應用帶來了便利。從Spring 3.0 開始, FactoryBean開始支持泛型,即接口聲明改成FactoryBean
在Spring 5.2.6版本中,FactoryBean接口的定義以下所示。緩存
package org.springframework.beans.factory; import org.springframework.lang.Nullable; public interface FactoryBean<T> { String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType"; @Nullable T getObject() throws Exception; @Nullable Class<?> getObjectType(); default boolean isSingleton() { return true; } }
這裏,須要注意的是:當配置文件中
首先,建立一個PersonFactoryBean,實現FactoryBean接口,以下所示。微信
package io.mykit.spring.plugins.register.bean; import org.springframework.beans.factory.FactoryBean; /** * @author binghe * @version 1.0.0 * @description 商品的FactoryBean,測試FactoryBean */ public class PersonFactoryBean implements FactoryBean<Person> { //返回一個Person對象,這個對象會被註冊到Spring容器中 @Override public Person getObject() throws Exception { return new Person(); } @Override public Class<?> getObjectType() { return Person.class; } //bean是否爲單例;true:是;false:否 @Override public boolean isSingleton() { return true; } }
接下來,咱們在PersonConfig2類中加入PersonFactoryBean的聲明,以下所示。框架
@Bean public PersonFactoryBean personFactoryBean(){ return new PersonFactoryBean(); }
這裏須要小夥伴們注意的是:我在這裏使用@Bean註解向Spring容器中添加的是PersonFactory對象。那咱們就來看看Spring容器中有哪些bean。接下來,運行SpringBeanTest類中的testAnnotationConfig7()方法,輸出的結果信息以下所示。ide
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory personConfig2 io.mykit.spring.plugins.register.bean.Department io.mykit.spring.plugins.register.bean.Employee io.mykit.spring.plugins.register.bean.User io.mykit.spring.plugins.register.bean.Role person binghe001 personFactoryBean company
能夠看到,結果信息中輸出了一個personFactoryBean,咱們看下這個personFactoryBean究竟是個什麼鬼!此時,咱們對SpringBeanTest類中的testAnnotationConfig7()方法稍加改動,添加獲取personFactoryBean的代碼,並輸出personFactoryBean實例的類型,以下所示。學習
@Test public void testAnnotationConfig7(){ ApplicationContext context = new AnnotationConfigApplicationContext(PersonConfig2.class); String[] names = context.getBeanDefinitionNames(); Arrays.stream(names).forEach(System.out::println); Object personFactoryBean = context.getBean("personFactoryBean"); System.out.println("personFactoryBean實例的類型爲:" + personFactoryBean.getClass()); }
再次運行SpringBeanTest類中的testAnnotationConfig7()方法,輸出的結果信息以下所示。
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory personConfig2 io.mykit.spring.plugins.register.bean.Department io.mykit.spring.plugins.register.bean.Employee io.mykit.spring.plugins.register.bean.User io.mykit.spring.plugins.register.bean.Role person binghe001 personFactoryBean company personFactoryBean實例的類型爲:class io.mykit.spring.plugins.register.bean.Person
能夠看到,雖然我在代碼中使用@Bean註解注入的PersonFactoryBean對象,可是,實際上從Spring容器中獲取到的bean對象倒是調用PersonFactoryBean類中的getObject()獲取到的Person對象。
看到這裏,是否是有種豁然開朗的感受!!!
在PersonFactoryBean類中,咱們將Person對象設置爲單實例bean,接下來,咱們在SpringBeanTest類中的testAnnotationConfig7()方法屢次獲取Person對象,並輸出屢次獲取的對象是否爲同一對象,以下所示。
@Test public void testAnnotationConfig7(){ ApplicationContext context = new AnnotationConfigApplicationContext(PersonConfig2.class); String[] names = context.getBeanDefinitionNames(); Arrays.stream(names).forEach(System.out::println); Object personFactoryBean1 = context.getBean("personFactoryBean"); Object personFactoryBean2 = context.getBean("personFactoryBean"); System.out.println(personFactoryBean1 == personFactoryBean2); }
運行testAnnotationConfig7()方法輸出的結果信息以下所示。
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory personConfig2 io.mykit.spring.plugins.register.bean.Department io.mykit.spring.plugins.register.bean.Employee io.mykit.spring.plugins.register.bean.User io.mykit.spring.plugins.register.bean.Role person binghe001 personFactoryBean company true
能夠看到,在PersonFactoryBean類的isSingleton()方法中返回true時,每次獲取到的Person對象都是同一個對象,說明Person對象是單實例bean。
這裏,可能就會有小夥伴要問了,若是將Person對象修改爲多實例bean呢?別急,這裏咱們只須要在PersonFactoryBean類的isSingleton()方法中返回false,便可將Person對象設置爲多實例bean,以下所示。
//bean是否爲單例;true:是;false:否 @Override public boolean isSingleton() { return false; }
再次運行SpringBeanTest類中的testAnnotationConfig7()方法,輸出的結果信息以下所示。
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory personConfig2 io.mykit.spring.plugins.register.bean.Department io.mykit.spring.plugins.register.bean.Employee io.mykit.spring.plugins.register.bean.User io.mykit.spring.plugins.register.bean.Role person binghe001 personFactoryBean company false
能夠看到,最終結果返回了false,說明此時Person對象是多實例bean。
以前,咱們使用@Bean註解向Spring容器中註冊的PersonFactoryBean,獲取出來的確實Person對象。那麼,小夥伴們可能會問:我就想獲取PersonFactoryBean實例,該怎麼辦呢?
其實,這也很簡單, 只須要在獲取bean對象時,在id前面加上&符號便可。
打開咱們的測試類SpringBeanTest,在testAnnotationConfig7()方法中添加獲取PersonFactoryBean實例的代碼,以下所示。
@Test public void testAnnotationConfig7(){ ApplicationContext context = new AnnotationConfigApplicationContext(PersonConfig2.class); String[] names = context.getBeanDefinitionNames(); Arrays.stream(names).forEach(System.out::println); Object personFactoryBean1 = context.getBean("personFactoryBean"); Object personFactoryBean2 = context.getBean("personFactoryBean"); System.out.println("personFactoryBean1類型:" + personFactoryBean1.getClass()); System.out.println("personFactoryBean2類型:" + personFactoryBean2.getClass()); System.out.println(personFactoryBean1 == personFactoryBean2); Object personFactoryBean3 = context.getBean("&personFactoryBean"); System.out.println("personFactoryBean3類型:" + personFactoryBean3.getClass()); }
運行SpringBeanTest類中的testAnnotationConfig7()方法,輸出的結果信息以下所示。
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory personConfig2 io.mykit.spring.plugins.register.bean.Department io.mykit.spring.plugins.register.bean.Employee io.mykit.spring.plugins.register.bean.User io.mykit.spring.plugins.register.bean.Role person binghe001 personFactoryBean company personFactoryBean1類型:class io.mykit.spring.plugins.register.bean.Person personFactoryBean2類型:class io.mykit.spring.plugins.register.bean.Person false personFactoryBean3類型:class io.mykit.spring.plugins.register.bean.PersonFactoryBean
能夠看到,在獲取bean時,在id前面加上&符號就會獲取到PersonFactoryBean實例對象。
那問題又來了!!爲何在id前面加上&符號就會獲取到PersonFactoryBean實例對象呢?
接下來,咱們就揭開這個神祕的面紗,打開BeanFactory接口,
package org.springframework.beans.factory; import org.springframework.beans.BeansException; import org.springframework.core.ResolvableType; import org.springframework.lang.Nullable; public interface BeanFactory { String FACTORY_BEAN_PREFIX = "&"; /**************如下省略n行代碼***************/ }
看到這裏,是否是明白了呢?沒錯,在BeanFactory接口中定義了一個&前綴,只要咱們使用bean的id來從Spring容器中獲取bean時,Spring就會知道咱們是在獲取FactoryBean自己。
好了,我們今天就聊到這兒吧!別忘了給個在看和轉發,讓更多的人看到,一塊兒學習一塊兒進步!!
項目工程源碼已經提交到GitHub:https://github.com/sunshinelyz/spring-annotation
若是以爲文章對你有點幫助,請微信搜索並關注「 冰河技術 」微信公衆號,跟冰河學習Spring註解驅動開發。公衆號回覆「spring註解」關鍵字,領取Spring註解驅動開發核心知識圖,讓Spring註解驅動開發再也不迷茫。