Spring中FactoryBean的高級用法實戰(zhàn)教程
前言
FactoryBean
是 Spring 框架中的一個高級特性,它允許開發(fā)者通過自定義的方式控制對象的創(chuàng)建過程。當(dāng)需要編寫復(fù)雜的初始化邏輯,而這些邏輯不適合直接放在類的構(gòu)造函數(shù)或初始化方法中時,FactoryBean
提供了一個很好的解決方案。通過實現(xiàn) FactoryBean
接口,可以在一個單獨的方法(通常是 getObject()
)中封裝所有的初始化邏輯,并將這個邏輯的結(jié)果(即對象實例)返回給 Spring 容器。
FactoryBean
接口定義了三個關(guān)鍵方法:
T getObject()
: 返回由該工廠創(chuàng)建的對象的實例。boolean isSingleton()
: 指定返回的實例是否為單例。Class<?> getObjectType()
: 返回getObject()
方法返回的對象類型。
Spring 框架內(nèi)部廣泛使用 FactoryBean
,提供了超過50個 FactoryBean
的實現(xiàn),用于創(chuàng)建和配置各種復(fù)雜的對象。
下面基于 UserService
類,通過幾個實戰(zhàn)案例來展示 FactoryBean
的不同用法。
class UserService { public void save() { System.out.println("save user ...") ; } }
基本用法
在這個例子中,我們創(chuàng)建了一個簡單的 UserServiceFactoryBean
,用于創(chuàng)建 UserService
的實例。
@Component public class UserServiceFactoryBean implements FactoryBean<UserService> { @Override public UserService getObject() throws Exception { return new UserService(); } @Override public Class<?> getObjectType() { return UserService.class; } @Override public boolean isSingleton() { return true; // 默認(rèn)返回單例 } }
使用方式:
@Resource private UserService userService; // 直接注入 // 或者通過 ApplicationContext 獲取 ApplicationContext context = ...; UserService us = context.getBean(UserService.class);
創(chuàng)建多例對象
將 isSingleton()
方法返回 false
,以創(chuàng)建多例對象。
@Override public boolean isSingleton() { return false; // 返回非單例 }
此時,每次通過 Spring 容器獲取的 UserService
實例都將是新的,以下兩個Controller中注入的UserService將是兩個不同的對象:
@Component public class UserController { @Resource private UserService userService ; } @Component public class CommonService { @Resource private UserService userService ; }
創(chuàng)建代理
使用 FactoryBean
創(chuàng)建代理對象是一種常見用法,尤其是在需要為對象添加橫切關(guān)注點(如日志、事務(wù)管理等)時。
@Override public PersonService getObject() throws Exception { ProxyFactory factory = new ProxyFactory(new UserService()); factory.addAdvice(new MethodInterceptor() { @Override public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("Before method call"); Object result = invocation.proceed(); System.out.println("After method call"); return result; } }); return (UserService) factory.getProxy(); }
獲取原始 FactoryBean
有時候,可能需要獲取 FactoryBean
本身而不是它創(chuàng)建的對象。
// 通過類型獲取 UserServiceFactoryBean factoryBean = context.getBean(UserServiceFactoryBean.class); // 或者通過名稱獲取,添加 '&' 前綴 UserServiceFactoryBean factoryBeanByName = context.getBean("&userServiceFactoryBean");
利用 SPI 獲取對象
Spring 提供的 ServiceFactoryBean
和 ServiceListFactoryBean
可以方便地用于基于 SPI 機(jī)制的服務(wù)加載。
@Configuration public class AppConfig { @Bean public ServiceFactoryBean<DAO> daoFactoryBean() { ServiceFactoryBean<DAO> fb = new ServiceFactoryBean<>(); fb.setServiceType(Partition.class); return fb; } }
在 META-INF/services
目錄下創(chuàng)建與 Partition
接口全限定名對應(yīng)的文件,列出所有實現(xiàn)類的全限定名。Spring 將加載并實例化這些實現(xiàn)類,并通過 daoFactoryBean
提供訪問。
com.diguobobo.helper.IdPartition com.diguobobo.helper.DatePratition
容器中注入Partition時,將得到這里的第一個IdPartition實例。
ServiceListFactoryBean獲取所有SPI對象
如果你需要獲取 SPI 接口的所有實現(xiàn),而不是單個實現(xiàn),可以使用 ServiceListFactoryBean。這個 Bean 工廠會返回一個包含所有 SPI 實現(xiàn)的列表。配置方式與 ServiceFactoryBean 類似,但返回的將是一個列表,而不是單個對象。
@Configuration public class AppConfig { @Bean public ServiceListFactoryBean<DAO> daoListFactoryBean() { ServiceListFactoryBean<DAO> fb = new ServiceListFactoryBean<>(); fb.setServiceType(Partition.class); return fb; } } // 使用時注入List<Partition> @Autowired private List<Partition> daos;
FactoryBean應(yīng)用場景
1. 延遲初始化
默認(rèn)情況下,Spring容器中的Bean會在容器啟動時進(jìn)行初始化。但是,通過FactoryBean,你可以控制對象的創(chuàng)建時機(jī),直到真正需要該對象時才進(jìn)行創(chuàng)建。這可以通過在FactoryBean中實現(xiàn)特定的邏輯來延遲調(diào)用getObject()
方法實現(xiàn)。
2. 依賴注入的高級用法
FactoryBean允許開發(fā)者在依賴注入過程中進(jìn)行更精細(xì)的控制。例如,你可以根據(jù)特定的條件動態(tài)地選擇不同的Bean實例進(jìn)行注入,或者根據(jù)環(huán)境變量、配置屬性等動態(tài)地創(chuàng)建Bean實例。
3. 集成第三方庫
當(dāng)需要將第三方庫中的對象集成到Spring容器中時,如果這些對象的創(chuàng)建過程比較復(fù)雜或者不符合Spring的默認(rèn)Bean創(chuàng)建規(guī)則,你可以通過實現(xiàn)FactoryBean來封裝這些復(fù)雜的創(chuàng)建邏輯。這樣,就可以像使用其他Spring Bean一樣使用這些第三方庫中的對象了。
4. 自定義作用域
雖然FactoryBean本身并不直接提供作用域的定義(作用域通常由Spring容器管理),但你可以通過FactoryBean來控制對象的創(chuàng)建過程,從而實現(xiàn)自定義作用域的效果。例如,可以通過FactoryBean來管理具有自定義生命周期的對象,如數(shù)據(jù)庫連接、網(wǎng)絡(luò)會話等。
5. 工廠方法的封裝
有時可能需要使用某個類的靜態(tài)工廠方法來創(chuàng)建對象實例。雖然Spring支持通過@Bean
注解來引用靜態(tài)工廠方法,但實現(xiàn)FactoryBean提供了一種更加封裝和靈活的方式來處理這種情況。你可以在FactoryBean中實現(xiàn)調(diào)用靜態(tài)工廠方法的邏輯,并將FactoryBean本身注冊為Spring容器中的Bean。
6. 與AOP集成
FactoryBean可以與Spring的AOP(面向切面編程)功能集成,用于在對象創(chuàng)建過程中應(yīng)用橫切關(guān)注點(如事務(wù)管理、日志記錄等)。雖然通常這些橫切關(guān)注點會應(yīng)用在Bean的方法調(diào)用上,但通過在FactoryBean中實現(xiàn)特定的邏輯,你也可以在對象創(chuàng)建過程中應(yīng)用這些關(guān)注點。
7. 復(fù)雜依賴的解耦
復(fù)雜的應(yīng)用中,Bean之間可能存在復(fù)雜的依賴關(guān)系。通過實現(xiàn)FactoryBean,你可以將這些復(fù)雜的依賴關(guān)系封裝在FactoryBean內(nèi)部,從而簡化Bean之間的依賴關(guān)系。這樣,其他Bean只需要依賴于FactoryBean創(chuàng)建的實例,而不需要關(guān)心這些實例背后的復(fù)雜創(chuàng)建邏輯和依賴關(guān)系。
到此這篇關(guān)于Spring中FactoryBean的高級用法實戰(zhàn)的文章就介紹到這了,更多相關(guān)Spring FactoryBean用法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java將不同的List集合復(fù)制到另一個集合常見的方法
在Java中,有時候我們需要將一個List對象的屬性值復(fù)制到另一個List對象中,使得兩個對象的屬性值相同,這篇文章主要介紹了Java將不同的List集合復(fù)制到另一個集合常見的方法,需要的朋友可以參考下2024-09-09淺談spring-boot 允許接口跨域并實現(xiàn)攔截(CORS)
本篇文章主要介紹了淺談spring-boot 允許接口跨域并實現(xiàn)攔截(CORS),具有一定的參考價值,有興趣的可以了解一下2017-08-08