FactoryBean与BeanFactory
1.什么是FactoryBean,后缀是'Bean'证明本质上仍然是一个Bean,仍然要放入BeanFactory中,只是它实现了FactoryBean<T>接口;
2.特点:根据该Bean的id从BeanFactory中获取的实际上是getObject返回的对象,要获得该FactoryBean本身,获取时需要加上'&';
3.为什么要使用factoryBean? 由于继承这个接口之后可以从getObject中获取对象,所以可以对该Bean进行针对性的处理然后返回所需要的Bean,例如可以为Bean做代理。可以看这个例子,这个接口在Spring内部经常用到。
http://blog.csdn.net/linuu/article/details/50855446
4.针对面试会问到它与BeanFactory有什么区别,经过上面的分析,它们之间本来就不是一类概念。 FactoryBean是Bean的一种,它也是放入BeanFactory中进行管理的。现在我们想知道的是如果在App类中加入这个接口,会对之前文章分析的执行顺序产生什么影响。 示例如下:
App.java
package com.mycompany.app;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
public class App implements InitializingBean,FactoryBean<Object>
{
private App(){
System.out.println("App.App()");
}
private String says="App";
public String getSays() {
return says;
}
public void setSays(String says) {
this.says = says;
}
public void say(){
System.out.println("App.app():"+says);
}
/**
* 在构造函数和getset方法之后执行postProcessBeforeInitialization方法
*/
/*这个方法是InitializingBean在继承InitializingBean接口后,要实现的方法,顾名思义,是在
*属性设置之后进行一些操作*/
public void afterPropertiesSet() throws Exception {
System.out.println("App.afterPropertiesSet()");
}
/*这个方法是在Spring配置中通过init-method属性指定为该方法,然后才会执行,在afterPropertiesSet方法之后*/
public void initMethod(){
System.out.println("App.initMethod()");
}
/**
*在afterPropertiesSet和initMethod方法之后执行postProcessAfterInitialization方法
*/
/*FactoryBean测试*/
public Object getObject() throws Exception {
System.out.println("App.getObject()");
Map<String,Object> map = new HashMap<String, Object>();
map.put("test", "GetObject");
return map;
}
public Class<?> getObjectType() {
return new HashMap().getClass();
}
public boolean isSingleton() {
return true;
}
}
BeanFactoryPostProcessorAppTest.java
package com.mycompany.app;
import java.util.Map;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanFactoryPostProcessorAppTest {
public static void main(String[] args) {
@SuppressWarnings("resource")
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("SpringBean.xml");
Map map = (Map)applicationContext.getBean("app");
System.out.println("BeanFactoryPostProcessorAppTest.main():"+map.get("test").toString());
}
}
其他的几个类同上篇文章,不变。
然后开始分析,我们说可以用&id和id的方式从BeanFactory中获取分别获取到FactoryBean本身和getObject返回的对象。那么在BeanFactory中其究竟保存了哪些Bean。
1)首先
Bean的实例化是在refresh方法中的finishBeanFactoryInitialization中:
2)然后preInstantiateSingletons方法:
3)很清楚的看到,当Bean为FactoryBean时,会在beanName的前面加上'&', 我们再进入getBean方法:
看到这个带有'&'的name,然后把'&'去掉,赋值给beanName,接着
我们看到createBean这个方法实际上是创建bean,而所创建的Bean的名字就是BeanName,并没有'&'符号。后面的getObjectForBeanInstance的第一个参数就是名字为beanName的bean。 (所以说BeanFactory中保存的其实是没有'&'符号的,这和预加载的时候beanFactory中的beanName是一致的):
然后我们进入getObjectForBeanInstance方法:
这个时候传进来的name带有'&'符号, 而if语句中也说明了
A:如果句柄引用的是一般的bean,直接返回这个Bean句柄; (适用情景:正常的getBean())
B:或者引用的是factoryBean,而且有'&',直接返回这个Bean句柄; (适用情景:获得factoryBean本身,如getBean('&App'))
C:如果引用的是factoryBean,而且没有'&',继续下面的语句 (适用情景: 从ApplicationContext中getBean(),
如BeanFactoryPostProcessorAppTest.java中的getBean("app"))
不允许存在引用一般的bean,而且有‘&’符号,上面一个if已经说明了这一点。
4)接着我们分析if之后的语句
前面我们看到2)的然后preInstantiateSingletons方法,整个BeanFactory中bean的初始化都在for循环中,遍历BeanFactory中BeanNames,而且是beanFactory都被加上了'&'符号,所以就不存在上面的情况C ,只有当我们从applicationContext中getBean的时候才会出现情况C,如上面BeanFactoryPostProcessorAppTest.java。
后面就可以猜到了,逐层进入getObjectFromFactoryBean方法:
最后执行的是这个Bean中的getObject方法,到此分析就结束了。
5)运行结果如下,和我们的分析一致