Spring bean 之 FactoryBean
来源:互联网 发布:重庆邮电移通知乎 编辑:程序博客网 时间:2024/05/16 05:26
Spring中有两种类型的Bean,一种是普通Bean,另一种是工厂Bean,即FactoryBean。Spring FactoryBean是创建复杂的bean,一般的bean直接用xml配置即可,如果一个bean的创建过程中涉及到很多其他的bean和复杂的逻辑,用xml配置比较困难,这时可以考虑用FactoryBean.
这两种Bean都被容器管理,但工厂Bean跟普通Bean不同,其返回的对象不是指定类的一个实例,其返回的是该FactoryBean的getObject方法所返回的对象。在Spring框架内部,有很多地方有FactoryBean的实现类,它们在很多应用如(Spring的AOP、ORM、事务管理)及与其它第三框架(ehCache)集成时都有体现,下面简单分析FactoryBean的用法。
1、FactoryBean用法
1)实现FactoryBean接口
/** * Created by Carl on 2016/8/12. */public class FactoryBeanTest implements FactoryBean<Object> { private boolean flag; public void setFlag(boolean flag){ this.flag = flag; } // 返回这个Bean的实例 @Override public Object getObject() throws Exception { return flag ? "carl" : new Date(); } // 返回这个类类型 @Override public Class<?> getObjectType() { return flag ? String.class : Date.class; } // 是否为单例 @Override public boolean isSingleton() { return true; }}
2)配置XML将Bean纳入Spring管理
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="factoryBeanTest1" class="com.weimob.carl.user.dto.FactoryBeanTest"> <property name="flag" value="true" /> </bean> <bean id="factoryBeanTest2" class="com.weimob.carl.user.dto.FactoryBeanTest"> <property name="flag" value="false" /> </bean></beans>
3)Test
public class Main { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("application-test.xml"); String string = context.getBean("factoryBeanTest1", String.class); Date date = context.getBean("factoryBeanTest2", Date.class); System.out.println(string); System.out.println(date); }}
通过简单的测试可知,该类输出如下:
2、实现原理
大家都知道应该知道BeanFactory在Spring IOC中的作用.它定义了Spring容器的基本方法。其中就包含getBean.由上面的方法调用图我们就可以看到BeanFactory与FactoryBean的关系。下面我们具体看一看代码实现:
1)org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance
protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, RootBeanDefinition mbd) { // 如果这里不是对FactoryBean的调用,那么结束处理 if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) { throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass()); } // 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) || BeanFactoryUtils.isFactoryDereference(name)) { return beanInstance; } Object object = null; if (mbd == null) { 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中得到Bean object = getObjectFromFactoryBean(factory, beanName, !synthetic); } return object;}
2)org.springframework.beans.factory.support.FactoryBeanRegistrySupport#getObjectFromFactoryBean
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) { if (factory.isSingleton() && containsSingleton(beanName)) { synchronized (getSingletonMutex()) { // 从cache中获取这个对象 Object object = this.factoryBeanObjectCache.get(beanName); if (object == null) { // 从FactoryBean获取这个对象 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 (object != null && shouldPostProcess) { try { object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Post-processing of FactoryBean's singleton object failed", ex); } } this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT)); } } return (object != NULL_OBJECT ? object : null); } } else { // 从FactoryBean获取这个对象 Object object = doGetObjectFromFactoryBean(factory, beanName); if (object != null && shouldPostProcess) { try { object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex); } } return object; }}
3)org.springframework.beans.factory.support.FactoryBeanRegistrySupport#doGetObjectFromFactoryBean
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName) throws BeanCreationException { Object object; try { if (System.getSecurityManager() != null) { AccessControlContext acc = getAccessControlContext(); try { object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { @Override public Object run() throws Exception { // 最终调用FactoryBean.getObject()方法 return factory.getObject(); } }, acc); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { // 最终调用FactoryBean.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); } // Do not accept a null value for a FactoryBean that's not fully // initialized yet: Many FactoryBeans just return null then. if (object == null && isSingletonCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException( beanName, "FactoryBean which is currently in creation returned null from getObject"); } return object;}
现在大家是不是对FactoryBean与BeanFactory这2个在Spring中非常重要的2个对象理解的很清楚了。
3、FactoryBean的存在价值
上面返回的已经是作为工厂的FactoryBean生产的产品,而不是FactoryBean本身。这种FactoryBean的机制可以为我们提供一个很好的封装机制,比如封装Proxy、RMI/JNDI等。通过对FactoryBean实现过程的原理进行分析,相信大家会对getObject有很深刻的印象。这个方法就是主要的FactoryBean的接口,需要实现特定的工厂的生产过程,至于这个生产过程是怎么和IoC容器整合的,就是在上面的分析的内容。
4、FactoryBean与设计模式
下图是一个典型的工厂模式的UML图。在这里我们可以看看设计模式中的工厂模式,做一个对比,以加深对这些代码的理解。
对比两者的实现,可以看到FactoryBean类似于AbstractFactory抽象工厂,getObjectForBeanInstance()方法类似于createProductA()这样的生产接口,而具体的FactoryBean实现,如TransactionProxyFactoryBean,就是具体的工厂实现,其生成出的TransactionProxy就是”抽象工厂”模式对应的ConcreteProduct.有了抽象工厂设计模式的参考与对比。对FactoryBean的设计和实现就更容易理解一些了。
- Spring bean 之 FactoryBean
- spring FactoryBean配置Bean
- Spring - bean配置-FactoryBean
- Spring学习之使用factorybean获取bean实例
- Spring学习笔记之通过FactoryBean配置Bean
- spring中 FactoryBean和bean
- Spring中的bean,factoryBean,beanFactory
- 【Spring】使用FactoryBean配置Bean
- Spring之FactoryBean
- Spring之FactoryBean
- Spring之FactoryBean
- Spring之FactoryBean接口
- Spring之FactoryBean
- Spring之FactoryBean
- Spring之FactoryBean
- Spring之FactoryBean
- Spring之FactoryBean
- Spring之FactoryBean
- 博弈论专题——推理与动态规划相关博弈之POJ2348
- 大话设计模式学习笔记---依赖倒转原则
- HDU 2112 HDU Today
- 10.shell编程(10) --- 函数(2)
- iOS 教你写通用的description方法
- Spring bean 之 FactoryBean
- 面向对象设计原则:
- C#开发命名规范
- 基于haproxy 实现spark hiveserver2 ha
- boost 协程版 echo 服务器
- Codeforces Round #358 (Div. 2) D. Alyona and Strings(两个字符串中找出k段相同的,且总长度最大)
- NOIP 2000单词接龙 解题报告(爆搜)
- HDU 1009 FatMouse' Trade 贪心水题
- C++宏定义详解