本文共 16996 字,大约阅读时间需要 56 分钟。
什么是FactoryBean
?
根据FactoryBean
源码的注释,我们可以对FactoryBean
有如下大概的认识。
FactoryBean
是单个对象的工厂,可以做为spring中的bean。FactoryBean
如果作为spring的bean,如果没有显式指定,获取到的bean对象是根据FactoryBean#getObject
方法获取的对象。FactoryBean
支持单例和原型,可以根据需要在启动容器时实时或延迟创建对象。- Spring容器只负责管理
FactoryBean
实例的生命周期,而不负责管理由FactoryBean
创建的对象的生命周期。
如何使用FactoryBean
?
通常情况下,Spring使用反射通过调用bean的构造器方法实例化并初始化bean,在这种情况下,我们无法直接控制bean的创建。FactoryBean
作为一个工厂bean,作用便是自定义bean的创建。使用FactoryBean
时,需要我们定义一个类实现FactoryBean
作为spring中的bean,当我们根据名称获取bean时获取的是FactoryBean
创建的对象。
User
类及UserFactoryBean
类 @Getter@Setterpublic class User { public User(){ System.out.println("创建User中..."); } private Integer id; private String name;}public class UserFactoryBean implements SmartFactoryBean{ public UserFactoryBean() { } @Override public User getObject() throws Exception { return new User(); } @Override public Class getObjectType() { return User.class; } @Override public boolean isSingleton() { return true; } @Override public boolean isEagerInit() { return true; }}
bean定义如下:
测试类如下:
public class FactoryBeanDemo { public static void main(String[] args) { System.out.println("准备初始化BeanFactory"); String location = "classpath:/META-INF/beans.xml"; BeanFactory beanFactory = new ClassPathXmlApplicationContext(location); System.out.println("结束初始化BeanFactory"); Object userFactoryBean = beanFactory.getBean("&user"); System.out.println("根据bean名称 &user 获取到的bean实例:" + userFactoryBean); Object user1 = beanFactory.getBean("user"); System.out.println("根据bean名称 user 获取到的bean实例:" + user1); Object user2 = beanFactory.getBean("user"); System.out.println("根据bean名称 user 再次获取到的bean实例:" + user2); Class userFactoryBeanType = beanFactory.getType("&user"); System.out.println("根据bean名称 &user 获取到的bean类型:" + userFactoryBeanType); Class userType = beanFactory.getType("user"); System.out.println("根据bean名称 user 获取到的bean类型:" + userType); }}
打印结果如下:
准备初始化BeanFactory创建User中...结束初始化BeanFactory根据bean名称 &user 获取到的bean实例:com.zuhkp.spring.factory.domain.UserFactoryBean@323b36e0根据bean名称 user 获取到的bean实例:com.zuhkp.spring.factory.domain.User@44ebcd03根据bean名称 user 再次获取到的bean实例:com.zuhkp.spring.factory.domain.User@44ebcd03根据bean名称 &user 获取到的bean类型:class com.zuhkp.spring.factory.domain.UserFactoryBean根据bean名称 user 获取到的bean类型:class com.zuhkp.spring.factory.domain.User
在xml文件中我们定义了id为user,class为UserFactoryBean
的bean。根据打印结果可得出如下结论。
- 根据bean名称 &user 获取到了
UserFactoryBean
的实例和类型,表明FactoryBean
可作为Spring的bean,并且bean的名称以 & 开头时获取的是FactoryBean
本身。 - 根据bean名称 user 获取到的是
User
的实例和类型,表明如果bean的类型为FactoryBean
时,如果获取bean时指定的bean的名称不以 & 开头,获取的bean是FactoryBean
创建的bean的实例和管理的类型。 FactoryBean#isSingleton
方法返回true时,每次获取的bean都是同一个。SmartFactoryBean
是FactoryBean
的子接口,SmartFactoryBean#isEagerInit
方法返回true时,将在容器初始化时对FactoryBean
管理的对象实时初始化。
FactoryBean源码浅析
spring版本:5.2.6.RELEASE
public interface FactoryBean{ /** * BeanDefinition可以使用AttributeAccessor#setAttribute方法设置的属性的名称,以便可以推断bean的类型 * @since 5.2 */ String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType"; /** * 返回此工厂管理的对象的实例(可能是共享的或独立的)。 * 与BeanFactory一样,这允许同时支持Singleton和Prototype设计模式。 * 如果调用时此FactoryBean尚未完全初始化(例如,因为它涉及循环引用),则抛出相应的FactoryBeanNotInitializedException。 * 从Spring2.0开始,允许FactoryBeans返回空对象。工厂将把它视为要使用的正常值; * 在这种情况下,它不会再抛出FactoryBeanNotInitializedException。 * 现在鼓励FactoryBean实现根据需要抛出FactoryBeanNotInitializedException。 * * @return an instance of the bean (can be {@code null}) * @throws Exception in case of creation errors * @see FactoryBeanNotInitializedException */ @Nullable T getObject() throws Exception; /** * 返回此FactoryBean创建的对象类型,如果事先不知道,则返回null。 * 这允许用户在不实例化对象的情况下检查特定类型的bean,例如在autowiring上。 * 对于正在创建单例对象的实现,此方法应尽量避免创建单例对象;它应该预先估计类型。 * 对于原型,在这里返回一个有意义的类型也是可取的。 * 在完全初始化此FactoryBean之前可以调用此方法。它不能依赖于初始化期间创建的状态;当然,如果可用,它仍然可以使用这种状态。 * 注意:Autowiring只会忽略在这里返回null的factorybean。因此,强烈建议使用FactoryBean的当前状态正确地实现此方法。 * * @return the type of object that this FactoryBean creates, * or {@code null} if not known at the time of the call * @see ListableBeanFactory#getBeansOfType */ @Nullable Class getObjectType(); /** * 这个工厂管理的对象是单例的吗?也就是说,getObject()是否总是返回相同的对象(可以缓存的引用)? * * 注意:如果FactoryBean指示保存一个singleton对象,那么从getObject()返回的对象可能会被拥有的BeanFactory缓存。 * 因此,除非FactoryBean始终公开相同的引用,否则不要返回true。 *
* FactoryBean本身的singleton状态通常由拥有它的BeanFactory提供;通常,它必须在那里定义为singleton。 *
* 注意:这个返回false的方法不一定表示返回的对象是独立的实例。 * 扩展SmartFactoryBean接口的实现可以通过SmartFactoryBean.isPrototype()方法。 * 如果isSingleton()实现返回false,那么不实现此扩展接口的普通FactoryBean实现将始终返回独立实例。 * 默认实现返回true,因为FactoryBean通常管理一个singleton实例。 * * @return whether the exposed object is a singleton * @see #getObject() * @see SmartFactoryBean#isPrototype() */ default boolean isSingleton() {
return true; }}
FactoryBean字段
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
FactoryBean
只有一个字段OBJECT_TYPE_ATTRIBUTE,在获取bean的类型时使用。
FactoryBean方法
T getObject() throws Exception;
:获取FactoryBean管理的对象实例,每次调用可能返回相同或不同的对象。Class<?> getObjectType();
:获取FactoryBean管理的对象的类型,以便可以不实例化对象就可以获取bean的类型。default boolean isSingleton()
:FactoryBean管理的对象是否为单例,如果返回true,则每次调用getObject()
方法返回的都是同一个实例。
SmartFactoryBean源码浅析
SmartFactoryBean
是FactoryBean
的子接口,对FactoryBean
进行了扩展。
public interface SmartFactoryBeanextends FactoryBean { /** * 这个工厂管理的对象是原型吗?也就是说,getObject()是否总是返回一个独立的实例? * FactoryBean本身的原型状态通常由拥有它的BeanFactory提供;通常,它必须被定义为singleton。 * 此方法应该严格检查独立实例;对于作用域对象或其他类型的非单例、非独立对象,它不应返回true。 * 因此,这不仅仅是isSingleton()的倒置形式。 默认实现返回false。 * @return whether the exposed object is a prototype * @see #getObject() * @see #isSingleton() */ default boolean isPrototype() { return false; } /** * 这个FactoryBean是否期望立即初始化,也就是说,急切地初始化它自己以及期望它的singleton对象(如果有的话)的急切初始化? * 标准的FactoryBean不需要急于初始化:它的getObject()只会在实际访问时被调用,即使是在单例对象的情况下也是如此。 * 从这个方法返回true意味着应该急切地调用getObject(),也应该急切地应用后处理程序。 * 对于单例对象,这可能是有意义的,特别是如果后处理器希望在启动时应用。 默认实现返回false。 * @return whether eager initialization applies * @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory#preInstantiateSingletons() */ default boolean isEagerInit() { return false; }}
default boolean isPrototype()
:FactoryBean
管理的对象是否为prototype。default boolean isEagerInit()
:容器启动时是否初始化FactoryBean
管理的对象。
Spring对FactoryBean的应用
定义的FactoryBean类型的bean为什么获取到的是FactoryBean#getObject()返回的对象?
跟踪BeanFactory#getBean(String)
方法,spring获取bean时首先获取到bean实例,bean实例可能为普通的bean,也有可能是FactoryBean类型的bean,然后调用AbstractBeanFactory#getObjectForBeanInstance
方法进行进一步处理。AbstractBeanFactory#getObjectForBeanInstance
方法源码如下:
protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { //name以&开头 if (BeanFactoryUtils.isFactoryDereference(name)) { if (beanInstance instanceof NullBean) { return beanInstance; } //name以&开头,但是对应的bean实例不是FactoryBean,抛出异常 if (!(beanInstance instanceof FactoryBean)) { throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass()); } if (mbd != null) { mbd.isFactoryBean = true; } return beanInstance; } //name不以&开头,name对应的bean实例不是FactoryBean,直接返回bean实例 if (!(beanInstance instanceof FactoryBean)) { return beanInstance; } //name不以&开头,对应的bean实例是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()); object = getObjectFromFactoryBean(factory, beanName, !synthetic); } return object; }
这里发现bean的名称以&开头,并且bean的类型是FactoryBean
会直接返回。如果bean的名称不以&开头,并且bean的类型非FactoryBean
也会直接返回。否则会调用FactoryBeanRegistrySupport#getObjectFromFactoryBean
方法从FactoryBean中获取。这里也验证了为什么bean的名称以&开头获取的是FactoryBean
本身。
FactoryBeanRegistrySupport#getObjectFromFactoryBean
源码如下: protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName, boolean shouldPostProcess) { if (factory.isSingleton() && containsSingleton(beanName)) { //FactoryBean获取的对象为单例,并且当前已经包含了单例,才根据FactoryBean获取单例 synchronized (getSingletonMutex()) { Object object = this.factoryBeanObjectCache.get(beanName); if (object == null) { object = doGetObjectFromFactoryBean(factory, beanName); // TODO 什么情况下可以重复获取到? // 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)) { // TODO 什么时候能够执行到该位置? // 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); } } // FactoryBean管理的对象是single,并且FactoryBean也是singleton,则缓存 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; } }
如果FactoryBean在spring容器中为singleton,并且FactoryBean管理的对象也为singleton则会缓存FactoryBean管理的对象,获取FactoryBean管理的对象时优先从缓存中获取,否则调用FactoryBeanRegistrySupport#doGetObjectFromFactoryBean
方法,这个方法将会调用FactoryBean#getObject
获取FactoryBean管理的对象。
定义的FactoryBean类型的bean为什么获取到的是FactoryBean#getObjectType返回的类型?
跟踪BeanFactory#getType(String, boolean)
方法,由AbstractBeanFactory
进行实现,源码如下:
@Nullable public Class getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException { String beanName = transformedBeanName(name); // 先从singleton中获取对象类型 // Check manually registered singletons. Object beanInstance = getSingleton(beanName, false); if (beanInstance != null && beanInstance.getClass() != NullBean.class) { if (beanInstance instanceof FactoryBean && !BeanFactoryUtils.isFactoryDereference(name)) { return getTypeForFactoryBean((FactoryBean ) beanInstance); } else { return beanInstance.getClass(); } } // singleton和当前BeanFactory中的BeanDefinition不存在,从父BeanFactory中获取 // No singleton instance found -> check bean definition. BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // No bean definition found in this factory -> delegate to parent. return parentBeanFactory.getType(originalBeanName(name)); } RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); // 优先从装饰的BeanDefinition中获取类型 // Check decorated bean definition, if any: We assume it'll be easier // to determine the decorated bean's type than the proxy's type. BeanDefinitionHolder dbd = mbd.getDecoratedDefinition(); if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) { RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd); Class targetClass = predictBeanType(dbd.getBeanName(), tbd); if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) { return targetClass; } } Class beanClass = predictBeanType(beanName, mbd); // Check bean class whether we're dealing with a FactoryBean. if (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass)) { if (!BeanFactoryUtils.isFactoryDereference(name)) { //name不以&开头,但是bean的类型为FactoryBean,则从FactoryBean中获取bean的真实类型 // If it's a FactoryBean, we want to look at what it creates, not at the factory class. return getTypeForFactoryBean(beanName, mbd, allowFactoryBeanInit).resolve(); } else { return beanClass; } } else { //name不以&开头则直接返回获取预测的beanClass return (!BeanFactoryUtils.isFactoryDereference(name) ? beanClass : null); } }
AbstractBeanFactory#getType(String, boolean)
方法优先从singleton bean中获取类型,如果singleton bean 为FactoryBean,则调用FactoryBeanRegistrySupport#getTypeForFactoryBean
方法,#getTypeForFactoryBean
将调用FactoryBean#getObjectType
方法获取FactoryBean
管理的对象的类型。
AbstractBeanFactory#getTypeForFactoryBean(String, RootBeanDefinition, boolean)
方法,getTypeForFactoryBean
方法源码如下: protected ResolvableType getTypeForFactoryBean(String beanName, RootBeanDefinition mbd, boolean allowInit) { ResolvableType result = getTypeForFactoryBeanFromAttributes(mbd); if (result != ResolvableType.NONE) { return result; } if (allowInit && mbd.isSingleton()) { try { FactoryBean factoryBean = doGetBean(FACTORY_BEAN_PREFIX + beanName, FactoryBean.class, null, true); Class objectType = getTypeForFactoryBean(factoryBean); return (objectType != null) ? ResolvableType.forClass(objectType) : ResolvableType.NONE; } catch (BeanCreationException ex) { if (ex.contains(BeanCurrentlyInCreationException.class)) { logger.trace(LogMessage.format("Bean currently in creation on FactoryBean type check: %s", ex)); } else if (mbd.isLazyInit()) { logger.trace(LogMessage.format("Bean creation exception on lazy FactoryBean type check: %s", ex)); } else { logger.debug( LogMessage.format("Bean creation exception on non-lazy FactoryBean type check: %s", ex)); } onSuppressedException(ex); } } return ResolvableType.NONE; }
AbstractBeanFactory#getTypeForFactoryBean(String, RootBeanDefinition, boolean)
方法将优先调用AbstractBeanFactory#getTypeForFactoryBeanFromAttributes
方法,如果获取不到,FactoryBean为允许初始化的singleton则调用FactoryBeanRegistrySupport#getTypeForFactoryBean
方法。
AbstractBeanFactory#getTypeForFactoryBeanFromAttributes
方法源码如下: ResolvableType getTypeForFactoryBeanFromAttributes(AttributeAccessor attributes) { Object attribute = attributes.getAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE); if (attribute instanceof ResolvableType) { return (ResolvableType) attribute; } if (attribute instanceof Class) { return ResolvableType.forClass((Class ) attribute); } return ResolvableType.NONE; }
可以看到,在此使用了FactoryBean.OBJECT_TYPE_ATTRIBUTE
获取bean的类型。
Spring容器启动初始化FactoryBean流程
Spring容器启动时方法调用链如下:
AbstractApplicationContext#refresh
,refresh
--> AbstractApplicationContext#finishBeanFactoryInitialization
--> DefaultListableBeanFactory#preInstantiateSingletons
。 preInstantiateSingletons
方法将对singleton bean进行实例化,源码如下。 public void preInstantiateSingletons() throws BeansException { if (logger.isTraceEnabled()) { logger.trace("Pre-instantiating singletons in " + this); } // Iterate over a copy to allow for init methods which in turn register new bean definitions. // While this may not be part of the regular factory bootstrap, it does otherwise work fine. ListbeanNames = new ArrayList<>(this.beanDefinitionNames); // Trigger initialization of all non-lazy singleton beans... for (String beanName : beanNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isFactoryBean(beanName)) { Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); if (bean instanceof FactoryBean) { final FactoryBean factory = (FactoryBean ) bean; boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged((PrivilegedAction ) ((SmartFactoryBean ) factory)::isEagerInit, getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean ) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } } } else { getBean(beanName); } } } ...省略部分代码 }
可以看到,如果bean不是抽象类,并且bean是singleton,并且bean不是懒加载,就会对bean进行初始化。如果bean是FactoryBean,并且FactoryBean管理的bean不是懒加载,还将初始化FactoryBean管理的对象。
总结
日常开发中对FactoryBean的使用并不常见,然而了解FacotryBean可以让我们更清晰的了解spring的底层实现及提供的能力。本文首先对FactoryBean进行解读,然后对FactoryBean的使用场景及使用方式进行阐述,最后从源码角度分析Spring如何使用FactoryBean的,从而解答了样例中输出结果的原因。
转载地址:https://blog.csdn.net/zzuhkp/article/details/107025523 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!