Spring FactoryBean源码浅析

在Spring BeanFactory容器中管理两种bean  

1.标准Java Bean  

2,另一种是工厂Bean,   即实现了FactoryBean接口的bean  它不是一个简单的Bean 而是一个生产或修饰对象生成的工厂Bean

在向Spring容器获得bean时  对于标准的java Bean  返回的是类自身的实例 

而FactoryBean 其返回的对象不一定是自身类的一个实例,返回的是该工厂Bean的getObject方法所返回的对象

一个简单的例子

public class SayHelloFactoryBeanImpl implements FactoryBean {

	/**
	 * 返回该工厂生成的bean
	 */
	public Object getObject() throws Exception {
		return new ChinaSayHelloServiceImpl();
	}

	/**
	 * getObject返回对象对应的Class
	 */
	public Class getObjectType() {
		return ChinaSayHelloServiceImpl.class;
	}
	
	/**
	 * getObject返回的对象 是否是一个单例
	 */
	public boolean isSingleton() {
		return false;
	}
}
配置文件
<bean id="sayHelloFactoryBean" class="com.xx.service.impl.SayHelloFactoryBeanImpl" />
		ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"classpath:applicationContext-server.xml"}, true);
		//bean的 getObject方法 返回的对象
		Object object = context.getBean("sayHelloFactoryBean");
		System.out.println(object);

控制台输出

com.xx.service.impl.ChinaSayHelloServiceImpl@1f66cff

容器返回的是 bean getObject方法返回对象  而不是SayHelloFactoryBeanImpl自身的实例 当然可以用“&”符号转义 获得FactoryBean的自身实例

ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"classpath:applicationContext-server.xml"}, true);
		//可以用转义符"&"来获得FactoryBean本身实例		
		System.out.println(context.getBean("&sayHelloFactoryBean"));

控制台输出

com.xx.service.impl.SayHelloFactoryBeanImpl@75e4fc

下面看看FactoryBean是怎么实现的

Spring  FactoryBean接口定义

public interface FactoryBean {

	Object getObject() throws Exception;

	Class getObjectType();

	boolean isSingleton();
}

bean的实例化 是在AbstractBeanFactory getBean方法发生的

public Object getBean(String name, Class requiredType, Object[] args) throws BeansException {
		return doGetBean(name, requiredType, args, false);
	}
protected Object doGetBean(final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {
		// bean name处理  如果是以"&"开头  截取掉  
		final String beanName = transformedBeanName(name);
		Object bean = null;
		//单例的bean 只实例化一次  第一次实例化后会放到一个Map中 即singletonObjects map集合中  下次使用的时候直接拿
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			// FactoryBean 相关处理 在此方法发生
			//name 调用getBean时传入的参数 
			//beanName 截取"&"后的name
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

		else {
			...略
		}
		return bean;
}
	protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
		// 如果不是FactoryBean的相关调用 结束处理
		//isFactoryDereference 方法判断name 是不是以"&"开始  如果以"&"开始 返回true
		if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
			throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
		}
		if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
			return beanInstance;
		}
		Object object = null;
		//bean的定义为null
		if (mbd == null) {
			//缓存集合factoryBeanObjectCache中包含  当前bean getObject方法返回的实例  不需要在调用 直接返回
			object = getCachedObjectForFactoryBean(beanName);
		}
		if (object == null) {
			FactoryBean factory = (FactoryBean) beanInstance;
			//containsBeanDefinition方法->  bean的定义map beanDefinitionMap集合中 是否包含该bean的定义
			if (mbd == null && containsBeanDefinition(beanName)) {
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			// FactoryBean getObject触发   并缓存到factoryBeanObjectCache集合中
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}
	protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName, boolean shouldPostProcess) {
		//当前的factoryBean是否单例  并且  缓存singletonObjects‘Map中包含FactoryBean的自身实例
		if (factory.isSingleton() && containsSingleton(beanName)) {
			synchronized (getSingletonMutex()) {
				// factoryBeanObjectCache 缓存的是 getObject返回的对象
				Object object = this.factoryBeanObjectCache.get(beanName);
				if (object == null) {
					//getObject方法调用
					object = doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);
					//缓存 getObject方法返回的实例对象
					this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
				}
				return (object != NULL_OBJECT ? object : null);
			}
		}
		else {
			//getObject方法调用
			return doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);
		}
	}
	private Object doGetObjectFromFactoryBean(
			final FactoryBean factory, final String beanName, final boolean shouldPostProcess)
			throws BeanCreationException {
		AccessControlContext acc = AccessController.getContext();
		return AccessController.doPrivileged(new PrivilegedAction() {
			public Object run() {
				Object object;

				try {
					// 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);
				}
				if (object == null && isSingletonCurrentlyInCreation(beanName)) {
					throw new BeanCurrentlyInCreationException(
							beanName, "FactoryBean which is currently in creation returned null from getObject");
				}

				if (object != null && shouldPostProcess) {
					try {
						object = postProcessObjectFromFactoryBean(object, beanName);
					}
					catch (Throwable ex) {
						throw new BeanCreationException(beanName, "Post-processing of the FactoryBean's object failed", ex);
					}
				}

				return object;
			}
		}, acc);
	}

当一个受Spring容器管理的bean  如果实现了FactoryBean接口  在bean实例化(getBean)阶段  Spring会调用该bean的getObejct方法 返回的不一定是自身的实例

Spring 框架中有很多FactoryBean   例如RmiProxyFactoryBean, SqlMapClientFactoryBean. LocalSessionFactoryBean等都是通过FactoryBean getObject方法驱动起来的.对bean的生产 修饰做了很好的封装。

  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值