Spring 源码解析 - FactoryBean 获取 Bean 过程

一、FactoryBean

FactoryBeanSpring框架提供的一个核心接口之一,用来创建复杂或无法通过默认构造函数创建的对象。这种情况下通过实现FactoryBean接口,可以自定义实例化Bean的过程,包括Bean的对象类型、初始化、销毁等。

在应用场景中,可以使用 FactoryBean 集成第三方框架、开源库或是处理一些特殊的业务需求,将Bean的控制权交由我们灵活控制。

比如:通过FactoryBean 将创建对象的逻辑封装起来,而对于使用者则无感知,正常向 IOC 容器获取 Bean 即可。

如果想要获取 FactoryBean 自身的话,则可以在 beanName 前面加个 & 符号,这点我们会在后面的源码分析中体验出来。

下面是 FactoryBean 的组成:

public interface FactoryBean<T> {
    
    
    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
	
    @Nullable
    T getObject() throws Exception;

    @Nullable
    Class<?> getObjectType();

    default boolean isSingleton() {
    
    
        return true;
    }
}

对应三个核心方法的说明:

  • isSingleton(): 获取由FactoryBean创建的Bean实例是单例还是原型,默认为单例。
  • T getObject(): 获取由FactoryBean创建的Bean实例,如果isSingleton的作用域为单例,会将该实例进行缓存。
  • Class<?> getObjectType(): 获取由FactoryBean要创建Bean的类型。

下面简单体验下 FactoryBean 的使用:

@Component
public class FactoryBeanTest implements FactoryBean {
    
    

    @Override
    public Object getObject() throws Exception {
    
    
        return new TestABC();
    }

    @Override
    public Class<?> getObjectType() {
    
    
        return TestABC.class;
    }

    @Override
    public boolean isSingleton() {
    
    
        return true;
    }

    /**
     * 实际Bean
     */
    public static class TestABC{
    
    
    
    }
}

测试:

public class App {
    
    
    public static void main(String[] args) {
    
    
        ApplicationContext context = new AnnotationConfigApplicationContext("com.example.demo.bean");
        System.out.println(context.getBean("factoryBeanTest"));
        System.out.println(context.getBean("&factoryBeanTest"));
    }
}

在这里插入图片描述

可以看出如果以 & 符号开头则获取的是 FactoryBean 自身。

下面从源码的角度分析下,context.getBean 获取 Bean 的过程中是如何处理 FactoryBean 的。

二、源码解读

在本专栏的前面文章中有针对 Bean 创建过程进行源码分析,如果了解的应该知道实际 Bean 创建的逻辑在 AbstractBeanFactorydoGetBean 方法中,这里也是从 doGetBean 方法入手,如果对 Bean 创建过程不了解也可以参考下面这篇文章:

Spring 源码解析 - Bean创建过程 以及 解决循环依赖

doGetBean 方法中,首先会去单例池中查找是否存在,如果存在这里会使用 getObjectForBeanInstance 获取到最终的 Bean 实例:

在这里插入图片描述

如果此时单例池中没有的话,进行下面 Bean 实例初始化的过程,当实例化完成后同样也使用 getObjectForBeanInstance 获取到最终的 Bean 实例

在这里插入图片描述

这个方法看似不起眼,其实对于FactoryBean 起着关键的作用,下面就主要看下 getObjectForBeanInstance 方法:

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 (BeanFactoryUtils.isFactoryDereference(name)) {
    
    
		// 如果是 NullBean 直接返回
		if (beanInstance instanceof NullBean) {
    
    
			return beanInstance;
		}
		// 如果不是 FactoryBean 的话则抛出异常
		if (!(beanInstance instanceof FactoryBean)) {
    
    
			throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
		}
		if (mbd != null) {
    
    
			mbd.isFactoryBean = true;
		}
		// 返回 FactoryBean 自身
		return beanInstance;
	}

	// 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.
	// 当前的 bean实例不是 FactoryBean,则直接返回
	if (!(beanInstance instanceof FactoryBean)) {
    
    
		return beanInstance;
	}

	// 是 FactoryBean 的情况下
	Object object = null;
	if (mbd != null) {
    
    
		mbd.isFactoryBean = true;
	}
	else {
    
    
		// 从缓存中获取
		object = getCachedObjectForFactoryBean(beanName);
	}
	if (object == null) {
    
    
		// 转为 FactoryBean 类型
		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;
}

在该方法中,首先第一步对 name 进行判断,如果是以 & 开头,说明当前获取的是 FactoryBean 本身,如果此时 Bean 不是 NullBean 也不是 FactoryBean 则只有报错了。

下面如果不是 FactoryBean 类型,直接返回当前实例即可。

再下面逻辑肯定是 FactoryBean 类型了,如果缓存中不存在话则最终调用了 getObjectFromFactoryBean 方法来获取 Bean ,下面看到该方法中:

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
    
    
    // 如果 FactoryBean 里的 Bean 是单例模型, 并且单例池中存在
    if (factory.isSingleton() && containsSingleton(beanName)) {
    
    
        // 对单例池加锁
        synchronized (getSingletonMutex()) {
    
    
            //尝试从缓冲中获取Bean
            Object object = this.factoryBeanObjectCache.get(beanName);
            // 如果缓存中不存在
            if (object == null) {
    
    
                // 从 FactoryBean 中的 getObject() 获取 Bean
                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) {
    
    
                    // 如果缓存存在使用缓存中的Bean
                    object = alreadyThere;
                } else {
    
    
                    // 缓存中依然不存在,是否需要触发后通知
                    if (shouldPostProcess) {
    
    
                        if (isSingletonCurrentlyInCreation(beanName)) {
    
    
                            // Temporarily return non-post-processed object, not storing it yet..
                            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);
                    }
                }
            }
            // 返回实际的 Bean
            return object;
        }
    } else {
    
    
        // 如果不是单例模式 或 单例池中不存在
        // 从 FactoryBean 中获取 Bean
        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);
            }
        }
        // 返回实际的 Bean
        return object;
    }
}

这里有两个分支,FactoryBean 中的 Bean 是单例还是不是单例,也就是 isSingleton 方法是 true 还是 false ,如果是单例的话,则尝试通过 factoryBeanObjectCache 获取缓存对象,从这里就可以看出 FactoryBean 中的 Bean 的单例缓存是存在了 factoryBeanObjectCache 中,而不是 Spring 的单例池。

在该方法中实际获取 Bean 是通过 doGetObjectFromFactoryBean 方法,如果单例模式则将 Bean 放入 factoryBeanObjectCache 中缓存,如果不是单例,则直接返回获取到的 Bean ,下面看到 doGetObjectFromFactoryBean 方法中:

private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, 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 获取实际 Bean。
            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;
}

这里就比较直观了,通过调用 FactoryBeangetObject 方法获取到最终的 Bean 实例。

猜你喜欢

转载自blog.csdn.net/qq_43692950/article/details/131109087