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