3、FactoryBean核心源码

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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值