BeanFactory与FactoryBean,相信不少刚翻看Spring源码的同窗跟我同样很好奇这俩货怎么长得这么像,分别都是干啥用的。BeanFactory是Spring中Bean工厂的顶层接口,也是咱们常说的SpringIOC容器,它定下了IOC容器的一些规范和经常使用方法并管理着Spring中全部的Bean,今天咱们不讲它,咱们看一下后面那个FactoryBean。html
先说下FactoryBean和其做用再开始分析:首先它是一个Bean,但又不只仅是一个Bean。它是一个能生产或修饰对象生成的工厂Bean,相似于设计模式中的工厂模式和装饰器模式。它能在须要的时候生产一个对象,且不只仅限于它自身,它能返回任何Bean的实例。java
首发地址:https://www.guitu18.com/post/2019/04/28/33.htmlspring
上面的解释有点抽象,那么咱们浏览一遍FactoryBean在Spring中是怎么应用的就好懂了。咱们都知道在Spring中咱们的Bean都会被Spring的IOC容器所管理,在AbstractApplicationContext中有一个很重要的方法:refresh(),项目启动或重启的时候refresh()会调用getBean()初始化全部的Bean,这个getBean()最终会指向AbstractBeanFactory中的getBean()方法。设计模式
在AbstractBeanFactory中,不论是根据名称仍是根据类型,getBean()最终都会调用doGetBean(),在doGetBean()方法中一开始就获取了名称beanName和实例sharedInstance,这个方法太长,这里就贴前面两行。框架
String beanName = this.transformedBeanName(name); Object sharedInstance = this.getSingleton(beanName);
transformedBeanName(name)是为了获取Bean真正的名称,它会去掉name前面的'&'
,而getSingleton(beanName)是从父类容器singletonObjects中取的这个Bean的实例。在Spring中还有不少这样的容器,好比DefaultListableBeanFactory中的beanDefinitionMap,它就是的IOC容器真正保存Bean的地方,它是一个HashMap。相似的还有FactoryBeanRegistrySupport中的factoryBeanObjectCache等。ide
回到doGetBean()方法中,拿到sharedInstance后,后面的一大堆操做作了单例、多例等判断,最终会走到this.getObjectForBeanInstance(),关键部分就在这个方法中,进入方法代码。post
protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { if (BeanFactoryUtils.isFactoryDereference(name)) { if (beanInstance instanceof NullBean) { return beanInstance; } if (!(beanInstance instanceof FactoryBean)) { throw new BeanIsNotAFactoryException(this.transformedBeanName(name), beanInstance.getClass()); } } if (beanInstance instanceof FactoryBean && !BeanFactoryUtils.isFactoryDereference(name)) { Object object = null; if (mbd == null) { object = this.getCachedObjectForFactoryBean(beanName); } if (object == null) { FactoryBean<?> factory = (FactoryBean)beanInstance; if (mbd == null && this.containsBeanDefinition(beanName)) { mbd = this.getMergedLocalBeanDefinition(beanName); } boolean synthetic = mbd != null && mbd.isSynthetic(); object = this.getObjectFromFactoryBean(factory, beanName, !synthetic); } return object; } else { return beanInstance; } }
在上面的代码中有两个判断分别是beanInstance instanceof FactoryBean
和BeanFactoryUtils.isFactoryDereference(name)
,前面判断的是beanInstance是否属于FactoryBean或其子类的实例,后面这个方法判断name是否不为空且以&
开头。性能
public static boolean isFactoryDereference(@Nullable String name) { return name != null && name.startsWith("&"); }
若是beanInstance不属于FactoryBean或其子类的实例,或者name是以&
开头就直接返回实例对象beanInstance,不然进入到if分支中。在if分支里的各类if .. ==null
判断是为了提升性能,我们只挑关键部分看:object = this.getObjectFromFactoryBean(factory, beanName, !synthetic);
继续跟踪进去看代码。测试
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) { if (factory.isSingleton() && this.containsSingleton(beanName)) { synchronized(this.getSingletonMutex()) { Object object = this.factoryBeanObjectCache.get(beanName); if (object == null) { object = this.doGetObjectFromFactoryBean(factory, beanName); Object alreadyThere = this.factoryBeanObjectCache.get(beanName); if (alreadyThere != null) { object = alreadyThere; } else { if (shouldPostProcess) { if (this.isSingletonCurrentlyInCreation(beanName)) { return object; } this.beforeSingletonCreation(beanName); try { object = this.postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable var14) { throw new BeanCreationException(beanName, "Post-processing of FactoryBean's singleton object failed", var14); } finally { this.afterSingletonCreation(beanName); } } if (this.containsSingleton(beanName)) { this.factoryBeanObjectCache.put(beanName, object); } } } return object; } } else { Object object = this.doGetObjectFromFactoryBean(factory, beanName); if (shouldPostProcess) { try { object = this.postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable var17) { throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", var17); } } return object; } }
这里面也是作了不少判断,我们也只挑关键部分看。这里说一下我的想法,看源码的时候若是咱们一直追究全部的细节那会让咱们会越陷越深,掉入细节的无底洞,稍不留神脑回路跟不上就会蒙圈。咱们要学会找源码中的关键部分看,弄懂主要流程和本次看源码的目的的那部分就行。等咱们对Spring总体有了一个很好的理解以后,再回头看以前不懂的代码就会豁然开朗。在上面这个方法中不论是走上面的if分支仍是到下边的else中,关键部分就是object = this.doGetObjectFromFactoryBean(factory, beanName)
这段代码调用,继续点进去。ui
private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException { Object object; try { if (System.getSecurityManager() != null) { AccessControlContext acc = this.getAccessControlContext(); try { object = AccessController.doPrivileged(factory::getObject, acc); } catch (PrivilegedActionException var6) { throw var6.getException(); } } else { object = factory.getObject(); } } catch (FactoryBeanNotInitializedException var7) { throw new BeanCurrentlyInCreationException(beanName, var7.toString()); } catch (Throwable var8) { throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", var8); } if (object == null) { if (this.isSingletonCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName, "FactoryBean which is currently in creation returned null from getObject"); } object = new NullBean(); } return object; }
在这个方法中有一行关键代码:object = factory.getObject();
这个factory就是咱们传入的beanInstance
实例。绕了这么一大圈,getBean方法返回的竟然是咱们实现FactoryBean接口定义的getObject方法。
那么跟一开始对FactoryBean的描述印证了,FactoryBean是一个能生产或修饰对象生成的工厂Bean。一个Bean若是实现了FactoryBean接口,那么根据该Bean的名称获取到的其实是getObject()返回的对象,而不是这个Bean自身实例,若是要获取这个Bean自身实例,那么须要在名称前面加上'&'符号。
通常状况下,Spring经过反射机制利用
的class属性指定实现类实例化Bean,在某些状况下,实例化Bean过程比较复杂,若是按照传统的方式,则须要在 中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会获得一个简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户能够经过实现该接口定制实例化Bean的逻辑。FactoryBean接口对于Spring框架来讲占用重要的地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂Bean的细节,给上层应用带来了便利。从Spring3.0开始,FactoryBean开始支持泛型,即接口声明改成FactoryBean 的形式
原理弄明白了,下面经过代码测试验证上面的流程,先定义一个Bean实现FactoryBean接口。
@Component public class MyBean implements FactoryBean { private String message; public MyBean() { this.message = "经过构造方法初始化实例"; } @Override public Object getObject() throws Exception { MyBean myBean = new MyBean(); myBean.message = "经过FactoryBean.getObject()建立实例"; // 这里并不必定要返回MyBean自身的实例,能够是其余任何对象的实例 return myBean; } @Override public Class<?> getObjectType() { return MyBean.class; } public String getMessage() { return message; } }
MyBean实现了FactoryBean接口的两个方法,getObject()是能够返回任何对象的实例的,这里测试就返回MyBean自身实例,且返回前给message字段赋值。同时在构造方法中也为message赋值。而后测试代码中先经过名称获取Bean实例,打印message的内容,再经过'&'+名称获取实例并打印message内容。
@RunWith(SpringRunner.class) @SpringBootTest(classes = TestApplication.class) public class FactoryBeanTest { @Autowired private ApplicationContext context; @Test public void test() { MyBean myBean1 = (MyBean) context.getBean("myBean"); System.out.println("myBean1 = " + myBean1.getMessage()); MyBean myBean2 = (MyBean) context.getBean("&myBean"); System.out.println("myBean2 = " + myBean2.getMessage()); System.out.println("myBean1.equals(myBean2) = " + myBean1.equals(myBean2)); } }
myBean1 = 经过FactoryBean.getObject()初始化实例 myBean2 = 经过构造方法初始化实例 myBean1.equals(myBean2) = false
经过测试咱们发现获取的两个实例中的message的值不同,对比两个对象的引用也不相同。上述所讲关于FactoryBean的内容印证完毕,本文结束。