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;
}
}