FactoryBean是什么
FactoryBean是spring源码中一种特殊的bean,就如同这个Bean的中文翻译一样,是一个工厂Bean,是用来生成Bean的工厂
可以用来干什么
假如我们不希望spring帮助我们去New一个对象,但是又希望生成的对象能交给spring进行管理,那么我们可以去实现这个FactoryBean接口,重写其中的getObject方法这样就可以根据自己的逻辑去生成一个Bean对象
源码解析
FactoryBean
public interface FactoryBean<T> {
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
}
可以看到FactoryBean中主要有三个方法,着三个方法也就是我们去实现一个FactoryBean需要去实现的方法
getObject():用户可以在这里生产自己的Bean,然后由FactoryBean进行生产
getObjectType():生产对象的类型
isSingleton():生产的对象是否为单例
首先要清除FactoryBean,本身也是一个Bean,当我们去实现FactoryBean这个接口实现自己的FactoryBean之后,如果想让这个Bean 生效,也需要加上@Component这个注解,将这个Bean注册到spring 的容器,所以在spring启动的初期,这个FactoryBean是被当成一个普通的Bean加载到spring容器的,接下来介绍源码具体的实现
applicationContext.getBean("factoryBeanName");
例如使用getBean这个方法来获取FactoryBean生产的对象,根据方法的调用会进入到doGetBean
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
......
首先doGetBean做的处理就是transformedBeanName,这里进行名字的处理原因有很多,分为三种情况
1.我们传入的本来就是一个首字母小写的BeanName,这种情况其实不会进行处理,传入的字符和处理后的字符是相同的
2.传入的是FactoyBean的名字,那么我们会返回FactoayBean对应的首字母小写的名字
3.传入的是“&“加上FactoyBean的名字,那么我们返回的也是FactoryBean对应的首字母小写的名字
也就是说在这里spring会进行统一的处理,最后返回的都是类名对应首字母小写的名字
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
//日志信息省略...
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
尝试从单例池里面获取,这里就印证了前面说的话,FactoryBean在spring容器总也是作为一个普通bean来存储的,所以要获取也是同普通的bean一样从单例池里面进行获取,这里为了方便分析,假设我们自己实现的FactoryBean没有设置为懒加载,那么在这里是可以直接获取到的
再然后就会进入 getObjectForBeanInstance这个方法
在这个方法里面会做一个判断如下
public static boolean isFactoryDereference(@Nullable String name) {
return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
}
就是判断这个传入进来的名字是不是以BeanFactory.FACTORY_BEAN_PREFIX开始,这个符号就是“&”
如果是以这个符号开始那么就直接返回了,因为以”&“这个符号开始的话,我们要取出来的就是FactoryBean本身了
而这个bean在spring容器初始化的时候已经实例化了,所以我们通过前面的单例池就可以直接取出,这里也就能直接进行返回了
那么如果是FactoryBean但是不以“&”开头又会做什么处理呢?
object = getCachedObjectForFactoryBean(beanName);
spring会先在容器里面尝试去拿,这里是从一个叫做factoryBeanObjectCache的map里面去拿
这个map key:beanName value:getObject返回的方法
但是第一次拿肯定是拿不到的,因为bean的生命周期中是不涉及直接去调用FactoryBean的getObject方法的
那么紧接着,我们想获取到这个getObject返回出来的对象,那么我们只能先去创建,并加入缓存了
那么这样是不是可以理解为FactoryBean的getObject返回的实例是懒加载的呢?
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());
// 调用getObject方法得到对象并放入factoryBeanObjectCache中
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
在这个过程中其实还有一个比较重要的操作getMergedLocalBeanDefinition,这个在后面进行介绍
先介绍最重要的去getObject的方法getObjectFromFactoryBean(factory, beanName, !synthetic)
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
// 是不是单例的
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// 调用getObject方法得到一个对象
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 (shouldPostProcess) {
// 单例真正创建
if (isSingletonCurrentlyInCreation(beanName)) {
return object;
}
beforeSingletonCreation(beanName);
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
afterSingletonCreation(beanName);
}
}
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
在这里面首先通过调用我们重写的isSingleton方法判断是不是一个单例Bean,然后加锁,但是加锁之后,
Object object = this.factoryBeanObjectCache.get(beanName);
又从缓存里面拿了一遍,这里其实是可以看成双端检索,如果说缓存里面拿不到就会真正的去拿getObject返回的Bean了
取得这个Bean之后机会将这个Bean返回,至此也就得到了这个Bean
以上就是FactoryBean在spring中实现的原理和流程
这里还有一点需要注意,即使时单例的FactoryBean也不会放入单例池,而是专门有一个factoryBeanObjectCache去存储这类Bean
补充1
还有没有和FactoryBean一样,能通过new对象的方式返回一个bean呢?
当然时有的,@Bean就可以达成这个效果,但是@Bean不如FactoryBean强大,因为FactoryBean在使用的时候还可以去实现其他的接口,例如XXXAware,或者是后置处理器,又或者是生命周期接口等等等,所以相比@Bean,FactoryBean能做的事情更多!
补充2
上面说过继承自FactoryBean接口,从FactoryBean的getObject方法里面返回出来的对象是懒加载的,那么有没有非懒加载的getObject?
这个也是有的但是对应要实现的是 SmartFactoryBean
如下是 Spring在实例化Bean的 preInstantiateSingletons() 方法中的一段源码:
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
// eager:急切的意思,立马初始化
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
// 根据beanName去生成FactoryBean中所生成的Bean对象
getBean(beanName);
}
}
判断传过来的beanName是不是一个FactoryBean,如果是FactoryBean,还会去判断这个FactoryBean是不是一个
SmartFactoryBean,并且还会返回一个EagerInit 的属性
这个属性就与SmartFactoryBean 相关,SmartFactoryBean是FactoryBean的子类,在这个子类中多提供了一个isEagerInit()
表示当前FactoryBean的getObject()返回出来的对象是不是懒加载,如果不是懒加载就会直接进行创建