FactoryBean的使用及底層工作原理分析
大家好,我是冰點(diǎn),本節(jié)我們通過對FactoryBean 接口源碼解析,以及使用示例剖析,讓大家3分鐘了解FactoryBean的作用和底層工作原理。以及FactoryBean的使用場景,學(xué)以致用。

FactoryBean是Spring框架中的一個接口,用于創(chuàng)建和管理其他Bean實(shí)例的對象。
FactoryBean的底層工作原理是通過實(shí)現(xiàn)FactoryBean接口并實(shí)現(xiàn)其中的方法來創(chuàng)建和管理Bean實(shí)例。
1.FactoryBean接口源碼解析
public interface FactoryBean<T> {
// 獲取由此工廠創(chuàng)建的對象實(shí)例
T getObject() throws Exception;
// 獲取由此工廠創(chuàng)建的對象實(shí)例的類型
Class<?> getObjectType();
// 判斷由此工廠創(chuàng)建的對象實(shí)例是否為單例模式
default boolean isSingleton() {
return true;
}
}
getObject()方法:獲取由此工廠創(chuàng)建的對象實(shí)例,可以在此方法中編寫自定義的創(chuàng)建邏輯,例如從外部資源獲取對象實(shí)例。getObjectType()方法:獲取由此工廠創(chuàng)建的對象實(shí)例的類型,Spring框架可以利用此方法來確定依賴注入時需要注入的具體類型。isSingleton()方法:判斷由此工廠創(chuàng)建的對象實(shí)例是否為單例模式。默認(rèn)情況下,FactoryBean創(chuàng)建的對象實(shí)例是單例模式,但是可以通過覆蓋此方法來改變對象實(shí)例的作用域。
2.FactoryBean使用代碼示例
一個簡單的FactoryBean示例代碼,咱們創(chuàng)建一個隨機(jī)數(shù)生成器的實(shí)例:
import java.util.Random;
import org.springframework.beans.factory.FactoryBean;
public class RandomNumberFactoryBean implements FactoryBean<Random> {
private int seed;
public void setSeed(int seed) {
this.seed = seed;
}
@Override
public Random getObject() throws Exception {
return new Random(seed);
}
@Override
public Class<?> getObjectType() {
return Random.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
- RandomNumberFactoryBean實(shí)現(xiàn)了FactoryBean接口,并實(shí)現(xiàn)了getObject()、getObjectType()和isSingleton()方法。
- 在getObject()方法中,它返回了一個由seed屬性指定的隨機(jī)數(shù)生成器的實(shí)例。在getObjectType()方法中,它返回了該實(shí)例的類型,即Random類。在isSingleton()方法中,它指定了該實(shí)例是一個單例模式的Bean。
要使用注解方式實(shí)例化RandomNumberFactoryBean,可以使用@Configuration和@Bean注解。
首先,創(chuàng)建一個配置類,使用@Configuration注解標(biāo)記該類為配置類。然后,在該類中創(chuàng)建一個用于實(shí)例化RandomNumberFactoryBean的@Bean方法,如下所示:
import java.util.Random;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public RandomNumberFactoryBean myRandom() {
RandomNumberFactoryBean factoryBean = new RandomNumberFactoryBean();
factoryBean.setSeed(12345);
return factoryBean;
}
}
在這個示例中,AppConfig類使用@Configuration注解標(biāo)記為配置類。然后,它定義了一個名為myRandom的@Bean方法,該方法返回一個RandomNumberFactoryBean實(shí)例,并為其設(shè)置seed屬性值為12345。
最后,在Spring應(yīng)用程序中,使用AnnotationConfigApplicationContext類來加載該配置類,如下所示:
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MyApp {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Random random = context.getBean("myRandom", Random.class);
int number = random.nextInt();
System.out.println("Random number: " + number);
context.close();
}
}
在這個示例中,MyApp類使用AnnotationConfigApplicationContext類來加載AppConfig配置類,并從容器中獲取myRandom Bean實(shí)例。然后,它使用該實(shí)例生成一個隨機(jī)數(shù),并將其輸出到控制臺。
使用注解方式實(shí)例化RandomNumberFactoryBean與使用XML配置方式實(shí)例化它的區(qū)別在于,我們可以在@Bean方法中直接創(chuàng)建RandomNumberFactoryBean實(shí)例,并為其設(shè)置屬性值,而不需要使用XML配置文件。這種方式更加便捷和靈活,可以更方便地進(jìn)行測試和修改。
3. 核心幾個點(diǎn)
- 當(dāng)Spring容器啟動時,它會掃描應(yīng)用程序中的所有Bean定義,并實(shí)例化那些需要實(shí)例化的Bean。如果遇到實(shí)現(xiàn)了
FactoryBean接口的Bean定義,Spring將會為該Bean創(chuàng)建一個特殊的代理對象,以便在需要時調(diào)用FactoryBean的方法來創(chuàng)建實(shí)際的Bean實(shí)例。 - 當(dāng)需要使用由
FactoryBean創(chuàng)建的Bean時,Spring將會調(diào)用代理對象的getObject()方法來獲取實(shí)際的Bean實(shí)例。如果需要,Spring還可以調(diào)用代理對象的getObjectType()方法來確定實(shí)際Bean實(shí)例的類型。 - 如果
FactoryBean創(chuàng)建的Bean是單例模式,那么Spring將在第一次調(diào)用getObject()方法時創(chuàng)建實(shí)例,并將其緩存起來。以后每次調(diào)用getObject()方法時,都會返回同一個實(shí)例。如果FactoryBean創(chuàng)建的Bean不是單例模式,則每次調(diào)用getObject()方法時都會創(chuàng)建一個新的實(shí)例。
4. FactoryBean 到底能干什么
FactoryBean允許我們在創(chuàng)建Bean實(shí)例時編寫自定義的邏輯,并且可以通過其返回的實(shí)際Bean實(shí)例類型來實(shí)現(xiàn)更精細(xì)的依賴注入。同時,Spring框架還提供了一些內(nèi)置的FactoryBean實(shí)現(xiàn),例如ProxyFactoryBean和JndiObjectFactoryBean,可以幫助我們更方便地創(chuàng)建一些常見的Bean實(shí)例。
FactoryBean 是 Spring 框架中的一個接口,它可以創(chuàng)建和管理其他對象的實(shí)例。通過實(shí)現(xiàn) FactoryBean 接口,可以自定義對象的創(chuàng)建過程,可以實(shí)現(xiàn)一些特殊的功能。
FactoryBean 主要有以下作用:
- 動態(tài)創(chuàng)建對象:FactoryBean 可以根據(jù)配置的參數(shù)和條件,動態(tài)地創(chuàng)建對象。這樣可以根據(jù)不同的情況創(chuàng)建不同的對象實(shí)例。
- 對象的裝配和初始化:FactoryBean 可以對創(chuàng)建的對象進(jìn)行配置和初始化,可以通過設(shè)置不同的屬性值或者調(diào)用不同的方法來進(jìn)行裝配和初始化。
- 對象的代理和包裝:通過 FactoryBean 可以對創(chuàng)建的對象進(jìn)行代理和包裝,可以動態(tài)地增加或修改對象的功能。
- 對象的生命周期管理:FactoryBean 可以管理所創(chuàng)建的對象的生命周期,可以在對象創(chuàng)建前后執(zhí)行一些操作,可以在需要時銷毀對象。
- 對象的緩存和復(fù)用:FactoryBean 可以實(shí)現(xiàn)對象的緩存和復(fù)用,可以避免重復(fù)創(chuàng)建對象,提高性能。
下面給出幾種常見的 FactoryBean 的使用示例:
- 動態(tài)創(chuàng)建對象
public class MyFactoryBean implements FactoryBean<Object> {
@Override
public Object getObject() throws Exception {
// 根據(jù)配置或條件動態(tài)創(chuàng)建對象
if (someCondition) {
return new MyObject();
} else {
return new AnotherObject();
}
}
@Override
public Class<?> getObjectType() {
// 返回實(shí)際創(chuàng)建的對象的類型
return Object.class;
}
@Override
public boolean isSingleton() {
// 返回是否為單例對象
return true;
}
}
- 對象的裝配和初始化
public class MyFactoryBean implements FactoryBean<MyObject> {
private String name;
private int age;
@Override
public MyObject getObject() throws Exception {
// 創(chuàng)建對象并進(jìn)行裝配和初始化
MyObject myObject = new MyObject();
myObject.setName(name);
myObject.setAge(age);
return myObject;
}
@Override
public Class<?> getObjectType() {
return MyObject.class;
}
@Override
public boolean isSingleton() {
return true;
}
// 設(shè)置屬性值的方法
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
}
- 對象的代理和包裝
public class MyFactoryBean implements FactoryBean<MyObject> {
private MyObject target;
@Override
public MyObject getObject() throws Exception {
// 對目標(biāo)對象進(jìn)行代理和包裝
MyObjectProxy proxy = new MyObjectProxy(target);
return proxy.getProxy();
}
@Override
public Class<?> getObjectType() {
return MyObject.class;
}
@Override
public boolean isSingleton() {
return true;
}
// 設(shè)置目標(biāo)對象的方法
public void setTarget(MyObject target) {
this.target = target;
}
}
- 對象的緩存和復(fù)用
public class MyFactoryBean implements FactoryBean<MyObject> {
private static final Map<String, MyObject> objectCache = new ConcurrentHashMap<>();
private String key;
@Override
public MyObject getObject() throws Exception {
// 根據(jù) key 從緩存中獲取對象,如果不存在則創(chuàng)建并放入緩存
MyObject myObject = objectCache.get(key);
if (myObject == null) {
myObject = new MyObject();
objectCache.put(key, myObject);
}
return myObject;
}
@Override
public Class<?> getObjectType() {
return MyObject.class;
}
@Override
public boolean isSingleton() {
return true;
}
// 設(shè)置 key 值的方法
public void setKey(String key) {
this.key = key;
}
}
- 對象的延遲初始化
public class MyFactoryBean implements FactoryBean<MyObject>, InitializingBean {
private MyObject myObject;
@Override
public MyObject getObject() throws Exception {
return myObject;
}
@Override
public Class<?> getObjectType() {
return MyObject.class;
}
@Override
public boolean isSingleton() {
return true;
}
// 在初始化時創(chuàng)建對象
@Override
public void afterPropertiesSet() throws Exception {
myObject = new MyObject();
// 執(zhí)行初始化操作
myObject.init();
}
}
- 對象的銷毀和資源釋放
public class MyFactoryBean implements FactoryBean<MyObject>, DisposableBean {
private MyObject myObject;
@Override
public MyObject getObject() throws Exception {
return myObject;
}
@Override
public Class<?> getObjectType() {
return MyObject.class;
}
@Override
public boolean isSingleton() {
return true;
}
// 在銷毀時釋放資源
@Override
public void destroy() throws Exception {
// 執(zhí)行銷毀操作
myObject.release();
}
}
總結(jié)
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
springboot集成mybatis?plus和dynamic-datasource注意事項(xiàng)說明
這篇文章主要介紹了springboot集成mybatis?plus和dynamic-datasource注意事項(xiàng)說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01
springboot JPA?CriteriaBuilder?如何獲取指定字段
這篇文章主要介紹了springboot JPA CriteriaBuilder如何獲取指定字段,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12
關(guān)于java中可變長參數(shù)的定義及使用方法詳解
下面小編就為大家?guī)硪黄P(guān)于java中可變長參數(shù)的定義及使用方法詳解。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-12-12
java?啟動參數(shù)?springboot?idea詳解
這篇文章主要介紹了java?啟動參數(shù)?springboot?idea的相關(guān)知識,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-09-09
基于Java生成窮舉字典(數(shù)字+字母(大小寫)+字符)詳解
在密碼學(xué)、安全測試以及某些編程挑戰(zhàn)中,生成一個包含所有可能組合的字典文件是非常有用的,下面我們就來看看如何使用Java語言來生成一個包含數(shù)字、字母(大寫和小寫)以及特殊字符的窮舉字典吧2025-12-12
工作中禁止使用Executors快捷創(chuàng)建線程池原理詳解
這篇文章主要為大家介紹了工作中禁止使用Executors快捷創(chuàng)建線程池原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
解決使用RestTemplate時報(bào)錯RestClientException的問題
這篇文章主要介紹了解決使用RestTemplate時報(bào)錯RestClientException的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08

