一,FactoryBean和BeanFactory
- FactoryBean:首先它是一个Bean,但又不仅仅是一个Bean。它是一个能生产或修饰对象生成的工厂Bean,类似于设计模式中的工厂模式和装饰器模式。它能在需要的时候生产一个对象,且不仅仅限于它自身,它能返回任何Bean的实例。
- BeanFactory:是Spring中Bean工厂的顶层接口,也是我们常说的SpringIOC容器,它定下了IOC容器的一些规范和常用方法并管理着Spring中所有的Bean。
二,FactoryBean揭秘
定义一个FactoryBean用于生产A对象:
public class MyFactoryBean implements FactoryBean<A> {
@Override
public A getObject() throws Exception {
return new A();
}
@Override
public Class<?> getObjectType() {
return A.class;
}
}
在xml中把定义的MyFactoryBean注入进去:
<bean id="myFactoryBean" class="com.bobo.MyFactoryBean"></bean>
1,解析为beanDefinition
通过debug调试,当源码走完obtainFreshBeanFactory()
方法后,MyFactoryBean
已经解析为BeanDefinition
并且放入到BeanDefinitionMap
中:
2,实例化对象
继续调试,当我们走完finishBeanFactoryInitialization(beanFactory);
方法时可以看到MyFactoryBean
已经被实例化并且缓存到了singletonObjects
中:
结论:当IOC容器启动完之后,会把FactoryBean实例化并且缓存在singletonObjects
中,注意:这里实例化的并不是A对象
3,调试context.getBean(“myFactoryBean”)方法:
上面容器已经初始化完成,下面我们来通过测试代码来从spring容器中获取bean
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println(context.getBean("myFactoryBean"));
}
}
上面getBean会走到源码doGetBean
中:
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
/**
* 提取对应的beanName,很多人会认为此处直接使用即可,为什么还要进行转换呢?
* 原因在于当bean对象实现FactoryBean接口之后就会变成&beanName,同时如果存在别名,也需要把别名进行转换
*/
String beanName = transformedBeanName(name);
Object bean;
// 提前检查单例缓存中是否有手动注册的单例对象,跟循环依赖有关联
// 此处会获取到singletonObjects中缓存的MyBeanFactory实例对象
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
// 返回对象的实例,很多人理解不了这句话存在的意义,当你实现了FactoryBean接口的对象,需要获取具体的对象的时候就需要此方法来进行获取了
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
}
以上源码可以看到,Object sharedInstance = getSingleton(beanName);
这句代码是去一级缓存singletonObjects
中获取beanName
为myBeanFactory
的对象,此处很显然能获取到容器初始化时已经缓存好了。
这里虽然已经获取到了MyBeanFactory
对象,但是这并不是我们想要的,我们想要的是A对象。别急,这里还没完,我们继续向下看bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
源码:
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// 通过beanName判断是否有factoryBean的前缀
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {
mbd.isFactoryBean = true;
}
return beanInstance;
}
// 当我们有了bean的实例之后,这个实例可能是正常的bean,也可能是FactoryBean,如果是FactoryBean那么就直接创建实例,
// 但是如果用户想要直接获取工厂实例而不是工厂的getObject方法对应的实例,那么传入的参数应该加&前缀
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
// 尝试从缓存中加载bean
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// 将beanInstance转换为FactoryBean类型
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
if (mbd == null && containsBeanDefinition(beanName)) {
// 将存储xml配置文件的GernericBeanDefinition转换为RootBeanDefinition,如果指定BeanName是子Bean的话,同时会合并父类的相关属性
mbd = getMergedLocalBeanDefinition(beanName);
}
//判断当前bean是否是用户定义的,而不是应用程序本身定义的
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
String FACTORY_BEAN_PREFIX = "&";
public static boolean isFactoryDereference(@Nullable String name) {
return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
}
以上代码:如果name
是以&
开头的,那么意思是获取FactoryBean
的实例,则直接返回,如:
context.getBean("&myFactoryBean")
这样获取的是FactoryBean
实例。
但是此时我们获取的是这种形式:
context.getBean("myFactoryBean")
那么继续往下走:
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
// 从缓存中获取,如果能取到直接返回,否则调用doGetObjectFromFactoryBean方法获取实例
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
object = doGetObjectFromFactoryBean(factory, beanName);
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (containsSingleton(beanName)) {
// 把获取到的实例缓存到factoryBeanObjectCache中,下次再取时直接从集合中获取就行了
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
// 省略了后置处理器的调用
return object;
}
}
先从factoryBeanObjectCache
缓存中获取,如果缓存中没有那么调用doGetObjectFromFactoryBean()
方法:
private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
Object object;
// 直接调用getObject方法,返回具体的对象
object = factory.getObject();
return object;
}
通过factory.getObject()
直接回调到MyFactoryBean的getObject()
方法中
public class MyFactoryBean implements FactoryBean<A> {
@Override
public A getObject() throws Exception {
return new A();
}
@Override
public Class<?> getObjectType() {
return A.class;
}
}
直接获取到A对象,然后再缓存到factoryBeanObjectCache
中,最终返回的是A对象的实例。
如果是单例情况下,下次再获取就直接从factoryBeanObjectCache
缓存中取到了。
三,总结
- getBean(beanName):获取的是FactoryBean中getObject()方法返回的对象实例,其缓存在factoryBeanObjectCache中,第一次获取时才会创建(指的是默认单例对象)。
- getBean(&beanName):获取的是FactoryBean实例对象,其缓存在singletonObjects中,spring容器初始化完成就已经创建(指的是默认单例对象)。