spring源码系列(三):FactoryBean

13 篇文章 2 订阅
11 篇文章 0 订阅

1、FactoryBean源码详解

首先,我们来看看FactoryBean的源码:

package org.springframework.beans.factory;
/*
由BeanFactory中的某些对象实现的接口,BeanFactory是Spring IOC容器的核心;
如果bean实现了这个接口,它将被用作对象的工厂来公开,而不是直接作为bean实例来公开
实现了该接口的bean不能被作为一个普通的bean使用。
FactoryBean以bean的类型定义,但是它暴露的bean引用始终是由它通过getObject()方法创建的对象。
FactoryBean支持单例和原型,并且既能懒加载又能在启动时就加载,SmartFactoryBean接口允许公开更细粒度的型文元数据。
这个接口被spring框架本身中毒使用,例如org.springframework.aop.framework.ProxyFactoryBean
它也可以用于自定义组件;但是,这只适用于基础结构代码
FactoryBean是编程式接口,它的实现不应该依赖于注解驱动注入或其他反射的方法。
getObjectType和getObject调用可能在启动的时候就发生了,甚至比后置处理器要更早。
如果需要访问其他bean,实现BeanFactoryAware接口并通过编程的方式获取他们。

容器进负责管理FactoryBean实例的生命周期,而不管理由FactoryBean产生的bean的生命周期。
因此,被暴露的销毁bean的方法并不会被自动调用,FactoryBean需要实现DisposableBean接口并且将对象销毁方法的调用委托给它。

最后,FactoryBean对象参与BeanFactory创建的bean的同步。
通常不需要进行内部同步,只是为了在FactoryBean本身内进行延迟初始化

同时,我们可以看出FactoryBean接口还定义了泛型,可以直接产生对应类型的bean
*/
public interface FactoryBean<T> {
   	/*
   		在BeanDefinition中设置的属性的名字,工厂bean可以在无法从工厂bean类中推导出对象类型时发出信号通知
   	*/
    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
    /*
    	返回此工厂bean管理的对象的实例
    	与BeanFactory相同,支持单例和原型设计模式
    	如果在调用时FactoryBean没有被完全初始化(例如因为循环引用),将抛出异常
    	自从spring2.0开始,FactoryBean允许返回null对象,此时工厂将null当作普通的值使用。
    */
    @Nullable
	T getObject() throws Exception;
    /*
    	返回FactoryBean创建的bean的类型,如果类型无法被提前得知会返回null
    	这允许我们在不实例化对象就可以检查给定bean的特定类型,例如在自动注入的时候
    	对于创建单例对象的实现,此方法应该尽量避免创建单例对象,而应该提前估计类型,
    	对于原型,在这里返回一个有意义的类型也是可取的
    	
    	这个方法可以在FactoryBean被完全实例化之前调用
    	它不能依赖初始化过程中的状态,当然,如果可用的情况下它可以使用
    	注意:对于自动注入将会简单的忽略FactoryBeans并返回null
    	因此,强烈建议使用FactoryBean的当前状态正确地实现此方法。
    */
    @Nullable
	Class<?> getObjectType();
    /*
    	判断由FactoryBean管理的对象是否为单例的,如果是的话总是返回同一个对象的引用(这个引用可以被缓存)
    	注意:如果FactoryBean实例持有单例对象,那么从getObject方法返回的对象可能会从BeanFactory的缓存中获取。
    	因此,不要返回true,除非FactoryBean总是暴露同样的引用
    	FactoryBean本身的单例状态通常由拥有它的BeanFactory提供,通常,它必须被定义为单例
    	注意:该方法返回false并不代表返回的对象是独立的对象
    	SmartFactoryBean中通常会通过isPrototype方法判断返回的对象是否为原型
    	如果isSingleton()实现返回false,那么没有扩展该接口的纯FactoryBean实现将会假定总是返回独立的实例。
    	该方法的默认实现返回true,因为FactoryBean通常管理单例实例
    */
    default boolean isSingleton() {
		return true;
	}   
}

通过上面源码的解读,我么可以发现FactoryBean主要是用于产生实际的bean。它的主要作用就是获取bean的实例、bean的类型、判断bean是否为单例。

借此来看,我们可以在FactoryBean中自定义我们需要的bean的创建过程,因为,我们可以通过FactoryBean#getObject()方法创建bean。

接下来,我们看看spring初始化过程是如何对FactoryBean进行操作的。

2、流程浅析

2.1 准备工作

首先准备需要调试的源码:

public interface FactoryBeanTest {
    /**
     * 测试
     * @return
     */
    void first();
}
public class FactoryBeanTestImpl implements FactoryBeanTest{
    @Override
    public void first() {
        System.out.println("我们来测试以下FactoryBean的调用时机");
    }
}
public class MyFactoryBean implements FactoryBean<FactoryBeanTest> {
    @Override
    public FactoryBeanTest getObject() throws Exception {
        return new FactoryBeanTestImpl();
    }

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

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

public class MyTest {
    public static void main(String[] args) {
        /*
        	bean生命周期
         */
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyFactoryBean.class);
        FactoryBeanTest bean = context.getBean(FactoryBeanTest.class);
        bean.first();
    }
}

以下流程默认大家掌握idea的调试技巧哦!

2.2 FactoryBean注册流程

首先来看看FactoryBean的整体注册流程:

image-20210412145732364

调试堆栈调用过程。

image-20210412145939009

首先我们来看看beanFactory.preInstantiateSingletons()方法,该方法属于DefaultListableBeanFactory,这里只看关键代码:

	@Override
	public void preInstantiateSingletons() throws BeansException {
		if (logger.isTraceEnabled()) {
			logger.trace("Pre-instantiating singletons in " + this);
		}

		// 获取所有bean的名称
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// 尝试加载所有非延迟初始化的bean
		for (String beanName : beanNames) {
            // 进行BeanDefinition的合并
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            // 如果bean为非抽象的、单例的、非懒加载的,那就加载bean
            // 懒加载就是使用的时候再加载它,在初始化的时候不进行加载
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                // 判断bean是否为FactoryBean,这里我们就是要看看FactoryBean的加载流程,所以这里直接进入该循环
				if (isFactoryBean(beanName)) {
                    // 通过getBean方法进行bean的加载操作,这里会给FactoryBean的bean名称加上前缀"&"
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                    // 如果bean属于FactoryBean的话,那么判断是否需要立即初始化
                    // 如果FactoryBean为SmartFactoryBean的话,才有可能要立即初始化
					if (bean instanceof FactoryBean) {
						FactoryBean<?> factory = (FactoryBean<?>) bean;
						boolean isEagerInit;
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
							isEagerInit = AccessController.doPrivileged(
									(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
									getAccessControlContext());
						}
						else {
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean<?>) factory).isEagerInit());
						}
						if (isEagerInit) {
							getBean(beanName);
						}
					}
				}
				else {
					getBean(beanName);
				}
			}
		}

		// 省略了其他代码
	}

接下来我们看看doGetBean方法:

	// 可以看出getBean方法实际调用了doGetBean方法
	public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args)
			throws BeansException {
		return doGetBean(name, requiredType, args, false);
	}

	protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {
        String beanName = transformedBeanName(name);
		Object bean;

        // 首先从单例缓存中检查是否已经加载bean
		Object sharedInstance = getSingleton(beanName);
        // 如果已经加载过直接调用getObjectForBeanInstance方法获取bean
        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 + "'");
				}
			}
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}
		else {
			// 省略了其他代码,有兴趣可以去看看源码哦!
			try {
                // 合并BeanDefinition
				RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);


				// 正式开始创建bean实例
				if (mbd.isSingleton()) {
                    // 再次调用了getSingleton的重载方法,最终代码会调用createBean方法
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							destroySingleton(beanName);
							throw ex;
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
                // 省略了其他代码
			}
        }
    	return (T) bean;
    }

我们接着来看看createBean方法,createBean对RootBeanDefinition做了一些验证以后,直接调用了doCreateBean方法,我们直接看这个方法:

// 实例化bean
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
    	// 如果当前bean是单例的,那就从factoryBeanInstanceCache缓存中
    	// 移除对应的BeanWrapper并返回给instanceWrapper
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
    	// 如果instanceWrapper为null,那就创建bean的实例,调用createBeanInstance方法
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
    	// 从instanceWrapper获得实例
		Object bean = instanceWrapper.getWrappedInstance();
    	// 获取instanceWrapper的类型
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		// Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
                    // 调用BeanDefinition的后置处理
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

		
    	// 缓存单例以便能够解析循环引用,即使由BeanFactoryAware之类的生命周期接口回调也能解决
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
    	// 如果允许解决循环引用,那么就调用addSingletonFactory方法,将暴露的早期bean加入到singletonFactories中
		if (earlySingletonExposure) {
			if (logger.isTraceEnabled()) {
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// 初始化bean的实例
		Object exposedObject = bean;
		try {
            // 进行属性bean实例的属性填充
			populateBean(beanName, mbd, instanceWrapper);
            // 初始化bean实例
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
			}
		}
		// 如果允许提前暴露单例就继续走下面的流程
		if (earlySingletonExposure) {
            // 调用getSingleton获取早期暴露的半成品bean实例
			Object earlySingletonReference = getSingleton(beanName, false);
            // 如果earlySingletonReference不为空,那么判断earlySingletonReference与bean是否相等,相等的话将earlySingletonReference赋值给它
			if (earlySingletonReference != null) {
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
                // 暂时还没读懂
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

		// Register bean as disposable.
    	// 为bean注册销毁时的调用方法
		try {
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}
		// 返回这个暴露的bean
		return exposedObject;
	}

当bean创建完成后,就会返回直接加入到singletonObjects中,此时这个bean就创建完成了,bean就走完了创建它的流程

2.3 getBean方法的流程

首先来看看方法的调用流程:

image-20210412162609306

getBean方法的调用堆栈:

image-20210412155850500

可以看到当我们调用context.getBean()方法获取FactoryBean类型的bean时,该方法最终会调用我们实现的FactoryBean接口。通过该接口的getObject()方法获取实际的bean,在本文中也就是FactoryBeanTestImpl()。

通过上面的方法调用链,大家可以自己去找对应的方法,看看每个方法的实际作用,这里由于笔者对于Spring的了解还不深,就不继续深入解析了,等以后悟了spring框架以后再补上这块内容!

3、总结

通过上面的源码分析,以及我们对程序的调试,可以发现:

  1. FactoryBean还是被当作bean被缓存到spring ioc容器的单例池中,也就是DefaultSingletonBeanRegistry类中的singletonObjects属性。这部分和普通的bean对象流程虽有差异,但是最终结果是一样的。
  2. 但是当我们调用getBean方法获取bean时,FactoryBean和普通的bean的获取流程就不一样了,这里会调用我们实现的FactoryBean里面的getObject()方法,在这个方法中,我们可以产生任何bean,这就是FactoryBean与普通bean的区别了!

感谢大家的阅读!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值