Spring中有兩種類型的Bean,一種是普通Bean,另一種是工廠Bean,即FactoryBean。Spring FactoryBean是創(chuàng)建復(fù)雜的bean,一般的bean直接用xml配置即可,如果一個(gè)bean的創(chuàng)建過程中涉及到很多其他的bean和復(fù)雜的邏輯,用xml配置比較困難,這時(shí)可以考慮用FactoryBean.
這兩種Bean都被容器管理,但工廠Bean跟普通Bean不同,其返回的對象不是指定類的一個(gè)實(shí)例,其返回的是該FactoryBean的getObject方法所返回的對象罚缕。在Spring框架內(nèi)部,有很多地方有FactoryBean的實(shí)現(xiàn)類,它們在很多應(yīng)用如(Spring的AOP蚊夫、ORM衣洁、事務(wù)管理)及與其它第三框架(ehCache)集成時(shí)都有體現(xiàn),下面簡單分析FactoryBean的用法呀狼。
1攒读、FactoryBean用法
1)實(shí)現(xiàn)FactoryBean接口
/**
* Created by Carl on 2016/8/12.
*/
public class FactoryBeanTest implements FactoryBean<Object> {
private boolean flag;
public void setFlag(boolean flag){
this.flag = flag;
}
// 返回這個(gè)Bean的實(shí)例
@Override
public Object getObject() throws Exception {
return flag ? "carl" : new Date();
}
// 返回這個(gè)類類型
@Override
public Class<?> getObjectType() {
return flag ? String.class : Date.class;
}
// 是否為單例
@Override
public boolean isSingleton() {
return true;
}
}
2)配置XML將Bean納入Spring管理
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="factoryBeanTest1" class="com.weimob.carl.user.dto.FactoryBeanTest">
<property name="flag" value="true" />
</bean>
<bean id="factoryBeanTest2" class="com.weimob.carl.user.dto.FactoryBeanTest">
<property name="flag" value="false" />
</bean>
</beans>
3)Test
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("application-test.xml");
String string = context.getBean("factoryBeanTest1", String.class);
Date date = context.getBean("factoryBeanTest2", Date.class);
System.out.println(string);
System.out.println(date);
}
}
通過簡單的測試可知,該類輸出如下:
2绸贡、實(shí)現(xiàn)原理
大家都知道應(yīng)該知道BeanFactory在Spring IOC中的作用.它定義了Spring容器的基本方法加袋。其中就包含getBean.由上面的方法調(diào)用圖我們就可以看到BeanFactory與FactoryBean的關(guān)系凛辣。下面我們具體看一看代碼實(shí)現(xiàn):
1)org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
// 如果這里不是對FactoryBean的調(diào)用,那么結(jié)束處理
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 這里從FactoryBean中得到Bean
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
2)org.springframework.beans.factory.support.FactoryBeanRegistrySupport#getObjectFromFactoryBean
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
// 從cache中獲取這個(gè)對象
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// 從FactoryBean獲取這個(gè)對象
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (object != null && shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
}
this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
}
}
return (object != NULL_OBJECT ? object : null);
}
}
else {
// 從FactoryBean獲取這個(gè)對象
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (object != null && shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
3)org.springframework.beans.factory.support.FactoryBeanRegistrySupport#doGetObjectFromFactoryBean
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
Object object;
try {
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
// 最終調(diào)用FactoryBean.getObject()方法
return factory.getObject();
}
}, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
// 最終調(diào)用FactoryBean.getObject()方法
object = factory.getObject();
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null && isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
return object;
}
現(xiàn)在大家是不是對FactoryBean與BeanFactory這2個(gè)在Spring中非常重要的2個(gè)對象理解的很清楚了。
3职烧、FactoryBean的存在價(jià)值
上面返回的已經(jīng)是作為工廠的FactoryBean生產(chǎn)的產(chǎn)品,而不是FactoryBean本身扁誓。這種FactoryBean的機(jī)制可以為我們提供一個(gè)很好的封裝機(jī)制,比如封裝Proxy、RMI/JNDI等蚀之。通過對FactoryBean實(shí)現(xiàn)過程的原理進(jìn)行分析蝗敢,相信大家會(huì)對getObject有很深刻的印象。這個(gè)方法就是主要的FactoryBean的接口足删,需要實(shí)現(xiàn)特定的工廠的生產(chǎn)過程寿谴,至于這個(gè)生產(chǎn)過程是怎么和IoC容器整合的,就是在上面的分析的內(nèi)容失受。
4讶泰、FactoryBean與設(shè)計(jì)模式
下圖是一個(gè)典型的工廠模式的UML圖。在這里我們可以看看設(shè)計(jì)模式中的工廠模式拂到,做一個(gè)對比痪署,以加深對這些代碼的理解。
對比兩者的實(shí)現(xiàn),可以看到FactoryBean類似于AbstractFactory抽象工廠,getObjectForBeanInstance()方法類似于createProductA()這樣的生產(chǎn)接口塞祈,而具體的FactoryBean實(shí)現(xiàn),如TransactionProxyFactoryBean辜王,就是具體的工廠實(shí)現(xiàn),其生成出的TransactionProxy就是"抽象工廠"模式對應(yīng)的ConcreteProduct.有了抽象工廠設(shè)計(jì)模式的參考與對比。對FactoryBean的設(shè)計(jì)和實(shí)現(xiàn)就更容易理解一些了罐孝。