关闭

Spring 源码梳理(五) FactoryBean与BeanFactory

标签: FactoryBean与BeanFactFactoryBeangetObject
205人阅读 评论(0) 收藏 举报
分类:

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)运行结果如下,和我们的分析一致


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:108083次
    • 积分:1827
    • 等级:
    • 排名:千里之外
    • 原创:83篇
    • 转载:25篇
    • 译文:1篇
    • 评论:30条