前言
上篇博客spring 5.0.x源码学习系列八: 实例化bean之应用构造方法创立bean、主动拆卸与循环依赖次要介绍了Spring bean的实例化过程,包含主动拆卸和依赖注入。其中有提到
FactoryBean
这个字眼,FactoryBean
是一种非凡的bean,它能够保护两个bean并都交由spring治理。但BeanFactory它并不是一个bean,是一个一般对象,通过new
关键字创立的。this.beanFactory = new DefaultListableBeanFactory();
- 这里先解释下bean和一般对象的概念
bean
: 通过spring创立,走了spring的bean创立过程一般对象
: new进去的,未通过spring的bean创立过程
一、我的项目demo
1.1 我的项目包构造
1.2 AppConfig.java
1.3 BeanA.java
1.4 Entry.java
1.5 MyFactoryBean.java
二、运行后果
三、原理解析
3.1 要想理解FactoryBean的原理首先得先理解FactoryBean的创立过程
3.1.1 创立FactoryBean入口
3.1.2 解决bean名称和第一次getSingleton
3.1.3 创立完FactoryBean
3.2 从getObjectForBeanInstance办法中获取真正须要的bean
源码及正文
protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { // Don't let calling code try to dereference the factory if the bean isn't a factory. // 判断未通过解决的bean名称是否为FactoryBean的个性, // 即是否以&符号结尾, 符合条件,然而if外部的两个条件都未满足,即可疏忽此段代码 if (BeanFactoryUtils.isFactoryDereference(name)) { if (beanInstance instanceof NullBean) { return beanInstance; } if (!(beanInstance instanceof FactoryBean)) { throw new BeanIsNotAFactoryException(beanName, 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. // 这个分支就是为了return一般的bean,此一般bean非一般bean // 这里的一般bean蕴含两种含意 // 1. 类型不是FactoryBean类型 // 2. 用户的目标就是想要获取FactoryBean类型的bean if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) { return beanInstance; } Object object = null; // 第二次获取context.getBean("myFactoryBean")时, 因为传入的mbd为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()); /** * 通过了上述条件的筛选,能进入此办法肯定是 * 要获取的bean为FactoryBean外部保护的对象。 * 在外部最重要的就是调用FactoryBean的getObject办法来获取bean。 * 第一次获取是调用FactoryBean的getObject办法返回并放入缓存中factoryBeanObjectCache */ object = getObjectFromFactoryBean(factory, beanName, !synthetic); } return object;}
3.2.1 从getObjectForBeanInstance办法中获取一般bean
- 这里的一般bean蕴含两种含意
- 类型不是FactoryBean类型的bean
- 用户的目标就是想要获取FactoryBean类型的bean
- 创立MyFactoryBean状况,属于上述第二种类型,及获取的bean类型就为FactoryBean, 所以它提前return
3.2.1.1获取MyFactoryBean状况: context.getBean("&myFactoryBean")
3.2.1.2 获取MyFactoryBean中保护的bean的状况: context.getBean("myFactoryBean")
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((PrivilegedExceptionAction<Object>) 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) { if (isSingletonCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException( beanName, "FactoryBean which is currently in creation returned null from getObject"); } object = new NullBean(); } return object;}
3.2.1.3 再次获取MyFactoryBean中保护的bean的状况:: context.getBean("myFactoryBean")
- 在main办法中新增一行代码
四、流程总结
4.1 创立FactoryBean流程
- 判断以后创立bean的类型为FactoryBean, 在bean名称前增加&符号
- 进入doGetBean办法, 对bean名称后面的&符号进行革除,外部保护了两个bean名称,一个是name另一个是beanName。其中name为真正创立的bean名称,beanName是解决过的bean名称。最终会以beanName去创立bean,所以FactoryBean对应的bean的名称就是首字母小写
创立完bean后对立走getObjectFromFactoryBean办法。在此办法中有四个参数都比拟重要:
beanInstance: 在doGetBean获取到的bean或者创立进去的bean对象name: 要获取真正bean的名称beanName: 解决过的bean名称(将name前的&符号去除)mbd: 由此参数决定是从缓存中获取bean还是从FactoryBean中调用getObejct办法获取bean
在创立FactoryBean的过程中, 因为name中蕴含了&符号, 则会在此代码中return, 最终将以后的FactoryBean返回实现bean的创立
// 在获取的bean跟FactoryBean无关的case下. 后面这个条件永远不会满足,因为首先不论是获取FactoryBean还是FactoryBean保护的bean,从spring单例池中获取的bean肯定为FactoryBean。最终再依据理论要获取的bean的名称来决定返回的是FactoryBean还是FactoryBean保护的beanif (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) { return beanInstance; }
4.2 获取FactoryBean流程
- 这里须要留神一个点: 不论是获取FactoryBean还是FactoryBean保护的bean。首先从spring单例池获取的bean都为FactoryBean,因为spring中没有一个bean会蕴含
&
符号,最终都是依据去除name中的&符号的beanName去获取bean。而后再依据以后bean的类型和name中是否蕴含&符号来确定返回的是FactoryBean还是FactoryBean保护的bean。所以咱们要想获取FactoryBean,要在beanName前增加&符号
这里还要留神下, 要获取FactoryBean外部保护的一个对象是间接通过它的getObject办法获取的以及后续是从一个缓存中获取的,这个保护的bean并没有走spring的生命周期。也就是说,假如保护的那个bean实现了InitializingBean接口,然而并没有回调到afterPropertiesSet办法
4.3 获取FactoryBean保护的bean流程
- 在下面的讲解下,
咱们要想获取到FactoryBean保护的bean,那就是beanName不能蕴含&符号
, 由下面的demo运行后果也能发现
五、小结
- 要获取FactoryBean则增加
&
符号。eg: context.getBean("&myFactoryBean") - 要获取FactoryBean保护的bean则不增加&符号。eg: context.getBean("myFactoryBean")
- 在上篇博客中也有提到FactoryBean的一些规定,此链接:https://github.com/AvengerEug/spring/tree/develop/resourcecode-study#%E5%8D%81%E4%B8%80-%E8%8E%B7%E5%8F%96factorybean%E5%AE%9E%E4%BE%8B%E4%B8%8E%E5%AE%83%E7%BB%B4%E6%8A%A4%E7%9A%84bean%E5%AE%9E%E4%BE%8B%E8%A7%84%E5%88%99 ,本片博客是对上述链接的一个扩大,内容基本一致