FactoryBean是什么
FactoryBean
是一个接口(位于org.springframework.beans.factory
包中),它的核心作用是通过编程方式动态创建Bean
。
FactoryBean与普通Bean的区别
- 普通的Bean由Spring根据BeanDefinition来创建;在创建时,会使用推断构造方法创建Bean,然后经过依赖注入、初始化、后置处理器处理等过程,最终返回或存入单例池中
- FactoryBean本身仍由Spring根据BeanDefinition来创建,但在通过
beanName
来获取bean时,会执行FactoryBean的getObject()方法来获取另一个真正的目标Bean。Spring会使用FacotryBean生成返回的Bean
典型应用场景
- 创建复杂的对象,比如Spring整合Mybatis中的
SqlSessionFactoryBean
- 集成第三方库时可以封装初始化逻辑
- 动态代理生成,如AOP代理
核心方法
因为FactoryBean是接口,其核心方法就三个
public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
/**
* 获取对象的方法
*/
@Nullable T getObject() throws Exception;
/**
* 获取对象方法返回的类型,需要和上面T类型一致
*/
@Nullable Class<?> getObjectType();
/**
* 是否是单例的
*/
default boolean isSingleton() {
return true;
}
}
使用示例
1、先创建一个UserFactoryBean
继承FactoryBean
并实现其方法,泛型为User
,这里isSingleton()
使用默认的true
单例
@Component
public class UserFactoryBean implements FactoryBean<User> {
@Override
public @Nullable User getObject() throws Exception {
User user = new User();
user.setName("小小");
return user;
}
@Override
public @Nullable Class<?> getObjectType() {
return User.class;
}
}
2、根据名字来获取使用User
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 这里就默认使用userFactoryBean作为名字
System.out.println(context.getBean("userFactoryBean"));
System.out.println(context.getBean("userFactoryBean"));
// 获取FactoryBean本身
System.out.println(context.getBean("&userFactoryBean"));
System.out.println(context.getBean("&userFactoryBean"));
}
3、当将isSingleton()
改为false
时,每次获取使用User
时都会返回新的Bean
FactoryBean相关源码
在Spring启动时,最终会调用到beanFactory中的instantiateSingleton(String beanName)
方法。在这个方法中会判断这个bean是否为factroyBean,如果是,会添加&符号在beanName前作为新beanName,然后调用getBean(String beanName)
方法生成factroyBean的实例
private void instantiateSingleton(String beanName) {
if (isFactoryBean(beanName)) {
// 判断当前的beanName是不是factoryBean,如果是,则获取带&的beanName的bean
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof SmartFactoryBean<?> smartFactoryBean && smartFactoryBean.isEagerInit()) {
getBean(beanName);
}
}
else {
getBean(beanName);
}
}
@Override
public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {
// 去掉name前面的&,获取beanName;没有&的话直接返回name
String beanName = transformedBeanName(name);
// 从单例池中尝试获取bean
Object beanInstance = getSingleton(beanName, false);
if (beanInstance != null) {
// 不为null,说明已经生成过了,判断是否是FactoryBean
return (beanInstance instanceof FactoryBean);
}
// No singleton instance found -> check bean definition.
// 没有单例bean,检查this.beanDefinitionMap中是否存在beanName的key
if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory cbf) {
// No bean definition found in this factory -> delegate to parent.
return cbf.isFactoryBean(name);
}
// 这里会通过mergedLocalBeanDefinition中的beanType和isFactoryBean来判断是否是FactoryBean
return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));
}
在getBean(String name)
方法中会调用doGetBean()
方法来获取Bean,这个方法就是Spring中创建Bean对象的一个核心方法。
- 先去除name前的"&“符号(多个会全部去除),没有”&"符号直接返回name。获取到beanName
- 从单例池中获取beanName对应的bean
- 第一次会获取不到,代码逻辑进入创建Bean的逻辑中来创建FactoryBean,此时的对应关系为 beanName->factoryBean
- 第二次在调用
getBean(String name)
时,单例池中存在对应的factoryBean,会获取到该factoryBean,然后调用factoryBean#getObject()
方法来获取真正的Bean,随后会将这个真正的Bean存入this.factoryBeanObjectCache
中,后面再获取时,会从this.factoryBeanObjectCache
中获取。
这里创建Bean的代码暂时不看,只看FactoryBean有关的代码
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object @Nullable [] args, boolean typeCheckOnly)
throws BeansException {
// 这里将name的将&去除
String beanName = transformedBeanName(name);
Object beanInstance;
// Eagerly check singleton cache for manually registered singletons.
// 1、factoryBean的类,这里在初始化时第一次为null,会走到下面else中去创建factoryBean的实例,然后将这个实例放入单例池中
// 这里在单例池中的对应关系 userFactoryBean -> userFactoryBean实例
// 当第一次通过getBean("userFactoryBean")来获取bean时候,此时单例池中的实例是userFactoryBean实例。这里就不为null,会进下面if中
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 1、注意这里传入的是userFactoryBean实例,name和beanName均是"userFactoryBean",mbd参数为null
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 创建bean逻辑......
return adaptBeanInstance(name, beanInstance, requiredType);
}
在上面的doGetBean()
方法中,会调用一个getObjectForBeanInstance()
来获取Bean对象,其中传入的最后一个参数为null。
在这个方法中:
- 先判断传入的name是否是"&"符号开头的,如果是,说明是要获取factoryBean本身,就将传入的bean实例返回。
- 如果不是,说明要得到FactoryBean的getObject()方法返回的对象。
- 先检查
factoryBeanObjectCache
中是否存在,也就是是否被创建过。如果有,则将cache中的返回 - 没有的话,接着调用
getObjectFromFactoryBean()
方法来获取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.
// 1、判断传入的name,也就是原始请求中传入的beanName是否是&符号开头的,如果是,表示要获取factoryBean,这里就将传入的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;
}
// 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.
// 1、 这里判断一下传入的bean实例是否是实现了FactoryBean接口的类,也就是是否是FactoryBean
// 如果是,这里就会直接利用JDK17语法糖强转成factoryBean;如果不是,则将原有的bean实例返回
if (!(beanInstance instanceof FactoryBean<?> factoryBean)) {
return beanInstance;
}
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
// 1、这里会从this.factoryBeanObjectCache中获取beanName的实例,第一次是为null的
// 但是当获取过一次之后,就会将创建出来的bean放入this.factoryBeanObjectCache中,之后再获取相同名字的bean,就从这里获取了
// 从某种意义上说,this.factoryBeanObjectCache也是一个单例池
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 当从this.factoryBeanObjectCache获取不到时,会调用这个方法来获得对应的bean,这里传入的factoryBean是已经强转过的传入的实例
object = getObjectFromFactoryBean(factoryBean, beanName, !synthetic);
}
return object;
}
在getObjectFromFactoryBean()
方法中会调用doGetObjectFromFactoryBean(factory, beanName)
其内部最核心的一行代码就是object = factory.getObject();
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
// factoryBean中isSingleton()方法返回的是true,同时在单例池中存在的
this.singletonLock.lock();
try {
// 1、再获取一遍,如果有缓存,直接返回缓存
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// 1、调用FactoryBean的getObject方法,获取对象
// 方法内最核心的一行代码就是object = factory.getObject();
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (for example, 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)) {
// 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);
}
}
// 这里会缓存对象到this.factoryBeanObjectCache中,下次再获取到对应的factoryBean时,就可以从这里获取到对应的对象
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
finally {
this.singletonLock.unlock();
}
}
else {
// 进这里的条件是factoryBean中的isSingleton()方法返回的是false。
// 这表示factoryBean创建的bean是非单例的。因此不会将对象缓存到this.factoryBeanObjectCache中,这样每次getBean()的时候,都会重新生成一个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);
}
}
return object;
}
}