spring中有兩種類型的Bean:一種是普通的JavaBean;另一種就是工廠Bean(FactoryBean),這兩種Bean都受Spring的IoC容器管理,但它們之間卻有一些區別。
普通的JavaBean不再多說,我們將其定義好,然後在配置文件中定義並配置其依賴關係,就可以通過IoC容器的getBean獲取到。
那麼FactoryBean呢?
FactoryBean跟普通Bean不同,它是實現了FactoryBean<T>接口的Bean,
1.通過BeanFactory類的getBean方法直接獲取到的並不是該FactoryBean的實例,而是該FactoryBean中方法getObject返回的對象。
2.但我們可以通過其它途徑獲取到該FactoryBean的實例,方法就是在通過getBean方法獲取實例時在參數name前面加上“&”符號即可。
FactoryBean接口提供的方法如下:
public interface FactoryBean<T> {
//獲取FactoryBean初始化的Bean實例
T getObject() throws Exception;
//獲取Bean實例的類型
Class<?> getObjectType();
//判斷是否是單例模式
boolean isSingleton();
}
通常會通過這種方式獲取到容器中的bean:
ApplicationContext appCtx = new ClassPathXmlApplicationContext("applicationContext.xml");
appCtx.getBean("myFactoryBean");
appCtx.getBean("&myFactoryBean");
通過跟代碼,會定位到org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)方法:
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
doGetBean方法中,會調用getObjectForBeanInstance來獲取給定的bean實例的對象,
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
.........//省略部分代碼
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
.........//省略部分代碼
return (T) bean;
}
getObjectForBeanInstance方法在AbstractBeanFactory的getObjectForBeanInstance方法
獲取給定bean實例的對象,對於FactoryBean,可以是bean實例本身,也可以是它創建的對象。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
//如果bean name是以&開始的,會直接返回beanInstance
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
//beanInstance不是FactoryBean,拋異常
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {
mbd.isFactoryBean = true;
}
return beanInstance;
}
// 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)) {
return beanInstance;
}
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
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獲取要公開的對象
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
其中BeanFactoryUtils.isFactoryDereference(name)源碼如下,只是判斷了開始是否是&開頭
String FACTORY_BEAN_PREFIX = "&";
public static boolean isFactoryDereference(@Nullable String name) {
return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
}
getObjectFromFactoryBean方法如下,用來從FactoryBean中獲取bean
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
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 (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
beforeSingletonCreation(beanName);
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
afterSingletonCreation(beanName);
}
}
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}