深入了解Spring中的FactoryBean
FactoryBean和BeanFactory由于在命名上極其相似,一直以來困擾了不少的開發(fā)者。
BeanFactory,耳熟能詳?shù)腟pring核心接口,提供IoC容器的最基本功能。但要解釋FactoryBean一句話可能就說不清楚了。我們將從下面的例子逐步說明,F(xiàn)actoryBean是什么,它提供了什么樣的能力。
/**
* 布料
* 包含顏色屬性
* Created by OKevin On 2019/9/3
**/
public class Cloth {
private Red red;
//省略setter/getter方法
}
當(dāng)初始化一個Cloth對象時,我希望Red對象也被賦值,此時我將在Cloth的構(gòu)造方法中new一個Red對象。
public Cloth() {
red = new Red();
}
但是隨著業(yè)務(wù)的發(fā)展,我希望Cloth的顏色屬性將是Blue藍(lán)色,這時我將修改代碼將Red和Blue類抽象出一個Color接口,Cloth代碼將重構(gòu):
/**
* 布料
* 包含顏色屬性
* Created by OKevin On 2019/9/3
**/
public class Cloth {
private Color color;
public Cloth() {
color = new Blue();
}
//省略setter/getter方法
}
業(yè)務(wù)又進(jìn)一步發(fā)展,Cloth類中的顏色屬性將會根據(jù)一定的條件賦值為Red紅色,此時我們將代碼繼續(xù)重構(gòu):
/**
* 布料
* 包含顏色屬性
* Created by OKevin On 2019/9/3
**/
public class Cloth {
private Color color;
public Cloth() {
if (condition()) {
color = new Blue();
} else {
color = new Red();
}
}
//省略setter/getter方法
}
這樣的代碼的確能運(yùn)行,但如果有新的條件繼續(xù)加入到業(yè)務(wù)中,此時我們又將改動Cloth類的構(gòu)造方法,而我們認(rèn)為Cloth方法是一個比較核心的業(yè)務(wù)對象,不應(yīng)該經(jīng)常對它進(jìn)行修改,并且在構(gòu)造方法中對于Color對象創(chuàng)建過于冗余,不符合單一職責(zé)的原則,所以我們將Color對象的創(chuàng)建過程通過工廠方法模式來完成。
靜態(tài)工廠方法
我們再次將Cloth類進(jìn)行如下重構(gòu)(為了使示例代碼更加簡潔,下面的示例將只創(chuàng)建Red對象):
/**
* 布料
* 包含顏色屬性
* Created by OKevin On 2019/9/3
**/
public class Cloth {
private Color color;
public Cloth() {
color = StaticColorFactory.newInstance();
}
//省略setter/getter方法
}
/**
* 靜態(tài)工廠方法
* Created by OKevin On 2019/9/3
**/
public class StaticColorFactory {
public static Color getInstance() {
return new Red();
}
}
如果我們在Spring容器中要通過靜態(tài)工廠方法,創(chuàng)建具體的對象實例應(yīng)該怎么做呢?
眾所周知,要將一個對象實例交由Spring容器管理,我們通常是通過以下XML配置:
<bean id="cloth" class="com.coderbuff.bean.Cloth"> <property name="color" ref="red"/> </bean> <bean id="red" class="com.coderbuff.bean.Red" />
但此時,Red對象實例并不是由Spring容器管理,而是由靜態(tài)工廠方法創(chuàng)建的,此時我們應(yīng)該講XML配置修改為以下方式:
<bean id="cloth" class="com.coderbuff.bean.Cloth"> <property name="color" ref="red"/> </bean> <bean id="red" class="com.coderbuff.factory.StaticColorFactory" factory-method="getInstance" />
這是Spring支持靜態(tài)工廠方法創(chuàng)建對象實例的特定方式。這樣我們就能在Spring中通過靜態(tài)工廠方法創(chuàng)建對象實例。
實例工廠方法
有靜態(tài)工廠方法,就有非靜態(tài)工廠方法,區(qū)別就是方法不是靜態(tài)的。
/**
* 實例工廠方法
* Created by OKevin On 2019/9/3
**/
public class ColorFactory {
public Color getInstance() {
return new Red();
}
}
實例工廠方法在Spring中XML配置略有不同:
<bean id="cloth" class="com.coderbuff.bean.Cloth"> <property name="color" ref="red"/> </bean> <bean id="colorFactory" class="com.coderbuff.factory.ColorFactory"/> <bean id="red" factory-bean="colorFactory" factory-method="getInstance"/>
通過配置可以看到,我們需要首先在Spring中實例化工廠,再通過工廠對象實例化Red對象。
在有了對工廠方法在Spring中創(chuàng)建對象實例的認(rèn)識后,F(xiàn)actoryBean實際上就是為我們簡化這個操作。下面我們將通過FactoryBean來創(chuàng)建Red對象。
FactoryBean
/**
* Created by OKevin On 2019/9/3
**/
public class ColorFactoryBean implements FactoryBean<Color> {
public Color getObject() throws Exception {
return new Red();
}
public Class<?> getObjectType() {
return Red.class;
}
public boolean isSingleton() {
return false;
}
}
通過實現(xiàn)FactoryBean的方式,XML配置如下:
<bean id="cloth" class="com.coderbuff.bean.Cloth"> <property name="color" ref="red"/> </bean> <bean id="red" class="com.coderbuff.factory.ColorFactoryBean"/>
這樣就不用像工廠方法那樣配置相應(yīng)的屬性,直接按照普通的Bean注入即可,由于Spring內(nèi)部做了特殊處理,此時名稱為“red”的Bean并不是ColorFactoryBean,而是它方法中g(shù)etObject中返回的對象。如果實在想要獲取ColorFactoryBean的對象實例,則在Bean的名稱前加入“&”即可(“&red”)。
看到這里,是否對FactoryBean有了一點認(rèn)識呢?FactoryBean在Spring中最為典型的一個應(yīng)用就是用來創(chuàng)建AOP的代理對象。
我們知道AOP實際上是Spring在運(yùn)行時創(chuàng)建了一個代理對象,也就是說這個對象,是我們在運(yùn)行時創(chuàng)建的,而不是一開始就定義好的,這很符合工廠方法模式。更形象地說,AOP代理對象通過Java的反射機(jī)制,在運(yùn)行時創(chuàng)建了一個代理對象,在代理對象的目標(biāo)方法中根據(jù)業(yè)務(wù)要求織入了相應(yīng)的方法。這個對象在Spring中就是——ProxyFactoryBean。
ProxyFactoryBean
我們將通過比較“古老”的方式創(chuàng)建一個Red對象的切面,在它的print方法執(zhí)行前和執(zhí)行后分別執(zhí)行一條語句。之所以古老是因為我們往往通過注解的方式,而不會這么折磨自己去寫一個切面對象。
/**
* 環(huán)繞通知
* Created by OKevin On 2019/9/4
**/
public class LogAround implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("調(diào)用目標(biāo)方法【前】打印日志");
Object result = invocation.proceed();
System.out.println("調(diào)用目標(biāo)方法【后】打印日志");
return result;
}
}
此時我們需要ProxyFactoryBean的介入為我們創(chuàng)建一個代理對象并由Spring容器管理,根據(jù)上面ColorFactoryBean的經(jīng)驗,ProxyFacoryBean也應(yīng)該如下配置:
<bean id="xxx" class="org.springframework.aop.framework.ProxyFactoryBean" />
答案是肯定的,只是ProxyFactoryBean多了幾個參數(shù),既然是生成代理對象,那么目標(biāo)對象、目標(biāo)方法就必不可少,實際的XLM配置如下:
<bean id="logAround" class="com.coderbuff.aop.LogAround"/> <bean id="red" class="com.coderbuff.bean.Red"/> <bean id="proxyRed" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces" value="com.coderbuff.bean.Color"/> <property name="interceptorNames" value="logAround"/> <property name="target" ref="red"/> <property name="proxyTargetClass" value="true"/> </bean>
通過測試程序,ProxyFactoryBean的確生成了一個代理對象。
public class ProxyFactoryBeanTest {
private ClassPathXmlApplicationContext ctx;
@Before
public void init() {
ctx = new ClassPathXmlApplicationContext("spring-proxyfactorybean.xml");
}
@Test
public void testProxyFactory() {
Red proxyRed = (Red) ctx.getBean("proxyRed");
proxyRed.print();
}
}
所以,F(xiàn)actoryBean為我們實例化Bean提供了一個更為靈活的方式,我們可以通過FactoryBean創(chuàng)建出更為復(fù)雜的Bean實例。
本文完整代碼地址:https://github.com/yu-linfeng/BlogRepositories/tree/master/repositories/factorybean
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Spring中BeanFactory與FactoryBean接口的區(qū)別詳解
- Spring?IOC容器FactoryBean工廠Bean實例
- Spring?BeanFactory?與?FactoryBean?的區(qū)別詳情
- Spring BeanFactory和FactoryBean區(qū)別解析
- spring如何通過FactoryBean配置Bean
- spring中的BeanFactory與FactoryBean的講解
- spring中FactoryBean中的getObject()方法實例解析
- spring中的FactoryBean代碼示例
- Spring詳細(xì)講解FactoryBean接口的使用
相關(guān)文章
詳解如何為SpringBoot項目中的自定義配置添加IDE支持
這篇文章主要介紹了詳解如何為SpringBoot項目中的自定義配置添加IDE支持,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02
關(guān)于Hadoop中Spark?Streaming的基本概念
這篇文章主要介紹了關(guān)于Hadoop中Spark?Streaming的基本概念,Spark?Streaming是構(gòu)建在Spark上的實時計算框架,它擴(kuò)展了Spark處理大規(guī)模流式數(shù)據(jù)的能力,Spark?Streaming可結(jié)合批處理和交互式查詢,需要的朋友可以參考下2023-07-07
Spring Boot整合Mybatis Plus和Swagger2的教程詳解
這篇文章主要介紹了Spring Boot整合Mybatis Plus和Swagger2的教程,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-02-02
spring cloud gateway 限流的實現(xiàn)與原理
這篇文章主要介紹了spring cloud gateway 限流的實現(xiàn)與原理,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-12-12
SpringBoot中yml多環(huán)境配置的3種方法
這篇文章主要給大家介紹了SpringBoot中yml多環(huán)境配置的3種方法,文中有詳細(xì)的代碼示例供大家參考,對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2023-10-10
Springboot?Vue實現(xiàn)單點登陸功能示例詳解
這篇文章主要為大家介紹了Springboot?Vue實現(xiàn)單點登陸功能示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01

