Spring - FactoryBean扩展接口
Posted 小小工匠
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring - FactoryBean扩展接口相关的知识,希望对你有一定的参考价值。
文章目录
- Pre
- org.springframework.beans.factory.FactoryBean
- FactoryBean中的设计模式----工厂方法模式
- FactoryBean VS BeanFactory
- 源码解析
- 扩展示例
Pre
org.springframework.beans.factory.FactoryBean
package org.springframework.beans.factory;
import org.springframework.lang.Nullable;
public interface FactoryBean<T>
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton()
return true;
一般情况下,Spring通过反射机制利用bean的class属性指定支线类去实例化bean,在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在bean中提供大量的配置信息。
配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean
的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。
FactoryBean
接口对于Spring框架来说占用重要的地位,Spring自身就提供了70多个FactoryBean
的实现。隐藏了实例化一些复杂bean的细节,给上层应用带来了便利。
从Spring3.0开始,FactoryBean
开始支持泛型,即接口声明改为FactoryBean<T>
的形式
FactoryBean中的设计模式----工厂方法模式
工厂方法模式是简单工厂模式的一种升级或者说是进一步抽象,它可以应用于更加复杂的场景,灵活性也更高。
在简单工厂中,由工厂类进行所有的逻辑判断、实例创建;
如果不想在工厂类中进行判断,可以为不同的产品提供不同的工厂,不同的工厂生产不同的产品,每一个工厂都只对应一个相应的对象,这就是工厂方法模式。
Spring 中的 FactoryBean 就是这种思想的体现,FactoryBean 可以理解为工厂 Bean
public interface FactoryBean<T>
T getObject();
Class<?> getObjectType();
boolean isSingleton();
我们定义一个类 ArtisanFactoryBean
来实现 FactoryBean
接口,主要是在 getObject
方法里 new
一个 Artisan
对象。这样我们通过 getBean(id)
获得的是该工厂所产生的 Artisan 的实例,而不是 ArtisanFactoryBean
本身的实例,像下面这样:
BeanFactory bf = new ClassPathXmlApplicationContext("artisan.xml");
Artisan artisanBean = (Artisan) bf.getBean("artisanFactoryBean");
FactoryBean VS BeanFactory
-
BeanFactory,就是bean的工厂,主要是通过定位、加载、注册以及实例化来维护对象与对象之间的依赖关系,以此来管理bean
-
FactoryBean,bean的一种,顾名思义,它也可以用来生产bean,也实现了相应的工厂方法。
-
一般来说,Bean是由BeanFactory生产,但FactoryBean的特殊之处就在于它也能生产bean。
-
获取FactoryBean的方法是
getBean("&"+beanName);
就是在beanName加个"&"前缀,若直接getBean(beanName),获取到的是FactoryBean通过getObject接口生成的Bean
。
源码解析
org.springframework.beans.factory.support.AbstractBeanFactory#getBean
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean
我们从 AbstractBeanFactory#doGetBean
梳理起来
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException
/**
* 通过name获取BeanName,这里不能使用name作为beanName:
* 1. name可能是别名,通过方法转换为具体的实例名称
* 2. name可能会以&开头,表明调用者想获取FactoryBean本身,而非FactoryBean创建bean
* FactoryBean 的实现类和其他的 bean 存储方式是一致的,即 <beanName, bean>,
* beanName 中是没有 & 这个字符的。所以我们需要将 name 的首字符 & 移除,这样才能从
* 缓存里取到 FactoryBean 实例。
*
*/
final String beanName = transformedBeanName(name);
Object bean;
// 从缓存中获取bean
Object sharedInstance = getSingleton(beanName);
/*
* 如果 sharedInstance = null,则说明缓存里没有对应的实例,表明这个实例还没创建。
*( BeanFactory 并不会在一开始就将所有的单例 bean 实例化好,而是在调用 getBean 获取bean 时再实例化,也就是懒加载)。
* getBean 方法有很多重载,比如 getBean(String name, Object... args),我们在首次获取
* 某个 bean 时,可以传入用于初始化 bean 的参数数组(args),BeanFactory 会根据这些参数
* 去匹配合适的构造方法构造 bean 实例。当然,如果单例 bean 早已创建好,这里的 args 就没有
* 用了,BeanFactory 不会多次实例化单例 bean。
*/
if (sharedInstance != null && args == null)
// 省略.....
/*
* 如果 sharedInstance 是普通的单例 bean,下面的方法会直接返回。但如果
* sharedInstance 是 FactoryBean 类型的,则需调用 getObject 工厂方法获取真正的
* bean 实例。如果用户想获取 FactoryBean 本身,这里也不会做特别的处理,直接返回
* 即可。毕竟 FactoryBean 的实现类本身也是一种 bean,只不过具有一点特殊的功能而已。
*/
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
/*
* 如果上面的条件不满足,则表明 sharedInstance 可能为空,此时 beanName 对应的 bean
* 实例可能还未创建。这里还存在另一种可能,如果当前容器有父容器,beanName 对应的 bean 实例
* 可能是在父容器中被创建了,所以在创建实例前,需要先去父容器里检查一下。
*/
else
// BeanFactory 不缓存 Prototype 类型的 bean,无法处理该类型 bean 的循环依赖问题
//判断是否存在循环依赖
if (isPrototypeCurrentlyInCreation(beanName))
throw new BeanCurrentlyInCreationException(beanName);
// 如果 sharedInstance = null,则到父容器中查找 bean 实例
BeanFactory parentBeanFactory = getParentBeanFactory();
// ......
try
// 合并父 BeanDefinition 与子 BeanDefinition
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// 检查是否有 dependsOn 依赖,如果有则先初始化所依赖的 bean
String[] dependsOn = mbd.getDependsOn();
// ......
// 创建 bean 实例
if (mbd.isSingleton())
/*
* 这里并没有直接调用 createBean 方法创建 bean 实例,而是通过
* getSingleton(String, ObjectFactory) 方法获取 bean 实例。
* getSingleton(String, ObjectFactory) 方法会在内部调用
* ObjectFactory 的 getObject() 方法创建 bean,并会在创建完成后,
* 将 bean 放入缓存中。
*/
sharedInstance = getSingleton(beanName, () ->
try
return createBean(beanName, mbd, args);
catch (BeansException ex)
destroySingleton(beanName);
throw ex;
);
// 如果 bean 是 FactoryBean 类型,则调用工厂方法获取真正的 bean 实例。否则直接返回 bean 实例
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
// 创建 prototype 类型的 bean 实例
else if (mbd.isPrototype())
// ......
// 创建其他类型的 bean 实例
else
// ......
// ......
return adaptBeanInstance(name, beanInstance, requiredType);
重点来了 getObjectForBeanInstance
。 在getObjectForBeanInstance
方法,它主要完成对获取的Bean Instance进行检测是否为FactoryBean
,如果是FactoryBean
则通过工厂方法获取Bean以及初始化后处理
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd)
// 判断name是否为Bean 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;
// beanInstance可能是普通的bena或者FactoryBean,如果是普通的Bean直接返回实例
if (!(beanInstance instanceof FactoryBean))
return beanInstance;
// 如果是FactoryBean,使用FactoryBean来创建一个bean实例
Object object = null;
if (mbd != null)
mbd.isFactoryBean = true;
else
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());
// 从FactoryBean中获取创建的Bean
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
return object;
先看看
public static boolean isFactoryDereference(@Nullable String name)
return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
FactoryBean创建的Bean的名称FactoryBean本身作为一个Bean在Spring容器中是用是否包含 &
前缀来区分的。
继续往下来
// 从FactoryBean中获取创建的Bean
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
org.springframework.beans.factory.support.FactoryBeanRegistrySupport#getObjectFromFactoryBean
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)
// 通过factory.getObject获取
object = doGetObjectFromFactoryBean(factory, beanName);
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null)
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))
//将获取到的对象放到factoryBeanObjectCache单例缓存map进行存储
this.factoryBeanObjectCache.put(beanName, object);
return object;
else
// 非单例模式,直接通过factory.getObejct获取,然后再返回给用户
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;
通过源码我们可以发现,无论是单例和非单例都会调用doGetObjectFromFactoryBean
方法,那毫无疑问就是生成bean对象的方法:
private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException
Object object;
try
// 系统安全处理器不为空
if (System.getSecurityManager() != null)
AccessControlContext acc = getAccessControlContext();
try
// 也是调用 factory::getObject
object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
catch (PrivilegedActionException pae)
throw pae.getException();
else
// 调用FactoryBean的getObject方法
object = factory.getObject();
catch ()
// ....
return object;
OK , DONE
扩展示例
package com.artisan.bootspringextend.testextends;
import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
/**
* @author 小工匠
* @version 1.0
* @description: TODO
* @date 2022/12/5 23:45
* @mark: show me the code , change the world
*/
@Slf4j
public class ExtendFactoryBean2
public static void main(String[] args)
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder
.genericBeanDefinition(UserServiceFactoryBean.class);
definitionBuilder.addPropertyValue("username", "artisan");
beanFactory.registerBeanDefinition("userService", definitionBuilder.getBeanDefinition());
UserService userService = (UserService) beanFactory.getBean("userService");
//artisan
log.info(userService.getUsername());
UserServiceFactoryBean userServiceFactoryBean = (UserServiceFactoryBean) beanFactory.getBean("&userService");
//artisan
log.info(userServiceFactoryBean.username);
public static class UserServiceFactoryBean implements FactoryBean<UserService>
@Setter
private String username;
@Override
public UserService getObject()
UserService userService = new UserService();
userService.setUsername(username);
return userService;
@Override
public Class<?> getObjectType()
return UserService.class;
@Setter
@Getter
public static class UserService
private String username;
定义一个UserServiceFactoryBean
,用来生产UserService
,将其注册到BeanFactory
中,如果使用UserService
对象,使用userService
的Bean
名称,
如果想要获取原来的UserServiceFactoryBean
对象,需要使用&userService
的Bean名称,&
这个前缀是Spring规定的,可以查看BeanFactory#FACTORY_BEAN_PREFIX
常量
00:05:24.692 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'userService'
00:05:24.762 [main] INFO com.artisan.bootspringextend.testextends.ExtendFactoryBean2 - artisan
00:05:24.762 [main] INFO com.artisan.bootspringextend.testextends.ExtendFactoryBean2 - artisan
Process finished with exit code 0
以上是关于Spring - FactoryBean扩展接口的主要内容,如果未能解决你的问题,请参考以下文章
Spring - FactoryBean扩展实战_MyBatis-Spring 启动过程源码解读
Spring - FactoryBean扩展实战_MyBatis-Spring 启动过程源码解读