Spring源码之FactoryBean接口的作用和实现原理

版权声明:本文为CSDN博主「桐花思雨」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_38192427/article/details/123320599

Spring源码之FactoryBean接口的作用和实现原

理?

1.factoryBean接口描述

BeanFactory 与 FactoryBean 接口,相信很多刚翻看 Spring 源码跟我一样很好奇这俩货怎么长得这么像,分别都是干啥用的。BeanFactory 是 Spring 中 Bean 工厂的顶层接口,也是我们常说的 Spring IOC 容器,它定下了 IOC 容器的一些规范和常用方法并管理着 Spring 中所有的 Bean,今天我们不讲它,我们看一下后面那个 FactoryBean

public interface FactoryBean<T> {

	@Nullable
	T getObject() throws Exception;

	@Nullable
	Class<?> getObjectType();

	default boolean isSingleton() {
		return true;
	}
}

先说下 FactoryBean 和其作用再开始分析:首先它是一个 Bean,但又不仅仅是一个 Bean。它是一个能生产或修饰对象生成的工厂 Bean,类似于设计模式中的工厂模式和装饰器模式。它能在需要的时候生产一个对象,且不仅仅限于它自身,它能返回任何 Bean 的实例

先说下 FactoryBean 和其作用再开始分析:

首先它是一个 Bean,但又不仅仅是一个 Bean。它是一个能生产或修饰对象生成的工厂 Bean,类似于设计模式中的工厂模式和装饰器模式。它能在需要的时候生产一个对象,且不仅仅限于它自身,它能返回任何 Bean 的实例

2.FactoryBean在Spring中的应用

在 Spring 中我们的 Bean 都会被 Spring 的 IOC 容器所管理,在 AbstractApplicationContext 中有一个很重要的方法:refresh(),项目启动或重启的时候 refresh() 会调用 getBean() 初始化所有的 Bean,这个 getBean() 最终会指向 AbstractBeanFactory 中的 getBean() 方法。上述方法的调用链过长,我们不过多赘述,
AbstractBeanFactory 抽象类中,不管是根据名称还是根据类型,getBean() 方法最终都会调用 doGetBean() 方法

2.1.doGetBean()

doGetBean() 方法中一开始就获取了名称 beanName 和实例 sharedInstance

@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
		@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

	final String beanName = transformedBeanName(name);
	Object bean;

	// 方法解释如下图
	Object sharedInstance = getSingleton(beanName);
	// 如果已经初始化过,直接从缓存中获取
	if (sharedInstance != null && args == null) {
		if (logger.isDebugEnabled()) {
			if (isSingletonCurrentlyInCreation(beanName)) {
				logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
						"' that is not fully initialized yet - a consequence of a circular reference");
			}
			else {
				logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
			}
		}	
		// 如果 sharedInstance 是普通的单例 bean,下面的方法会直接返回。但如果
		// 是 FactoryBean 类型的,则需调用 getObject 工厂方法获取真正的 bean 实例
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}
	else {
		// 如果是原型不应该在初始化的时候创建,在这里直接抛出异常
		if (isPrototypeCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
		BeanFactory parentBeanFactory = getParentBeanFactory();
		if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
			// 将别名解析成真正的beanName
			String nameToLookup = originalBeanName(name);
			// 如果parentBeanFactory存在,并且beanName在当前BeanFactory不存在Bean定义,则尝试从parentBeanFactory中获取bean实例
			if (parentBeanFactory instanceof AbstractBeanFactory) {
				return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
						nameToLookup, requiredType, args, typeCheckOnly);
			}
			// 尝试在parentBeanFactory中获取bean对象实例
			else if (args != null) {
				return (T) parentBeanFactory.getBean(nameToLookup, args);
			}
			else {
				return parentBeanFactory.getBean(nameToLookup, requiredType);
			}
		}
		if (!typeCheckOnly) {
			markBeanAsCreated(beanName);
		}
		try {
			// 根据beanName重新获取MergedBeanDefinition
			final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			checkMergedBeanDefinition(mbd, beanName, args);
			String[] dependsOn = mbd.getDependsOn();
			if (dependsOn != null) {
				// 遍历当前bean依赖的bean名称集合
				for (String dep : dependsOn) {
					// 检查dep是否依赖于beanName,即检查是否存在循环依赖
					if (isDependent(beanName, dep)) {
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
								"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
					}
					// 将dep和beanName的依赖关系注册到缓存中
					registerDependentBean(dep, beanName);
					try {
						getBean(dep);
					}
					catch (NoSuchBeanDefinitionException ex) {
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
								"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
					}
				}
			}
			// scope为 singleton 的bean创建
			if (mbd.isSingleton()) {
				sharedInstance = getSingleton(beanName, () -> {
					try {
						// 创建Bean实例
						return createBean(beanName, mbd, args);
					}
					catch (BeansException ex) {
						destroySingleton(beanName);
						throw ex;
					}
				});
				// 返回beanName对应的实例对象
				// 这里主要处理实现了FactoryBean的情况,需要调用重写的getObject()方法来获取实际的Bean实例
				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			}				
			// scope为 prototype 的bean创建
			else if (mbd.isPrototype()) {			
				Object prototypeInstance = null;
				try {
					// 创建实例前的操作(将beanName保存到prototypesCurrentlyInCreation缓存中)
					beforePrototypeCreation(beanName);
					// 创建Bean实例
					prototypeInstance = createBean(beanName, mbd, args);
				}
				finally {
					// 创建实例后的操作(将创建完的beanName从prototypesCurrentlyInCreation缓存中移除)
					afterPrototypeCreation(beanName);
				}
				// 返回beanName对应的实例对象
				// 这里主要处理实现了FactoryBean的情况,需要调用重写的getObject()方法来获取实际的Bean实例
				bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
			}
			else {
				// 既不是单例也不是原型的 bean创建,可能是 request之类的
				// 根据scopeName,从缓存拿到scope实例
				String scopeName = mbd.getScope();
				final Scope scope = this.scopes.get(scopeName);
				if (scope == null) {
					throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
				}
				try {
					// 既不是单例也不是原型的bean创建
					Object scopedInstance = scope.get(beanName, () -> {
						// 创建实例前的操作(将beanName保存到prototypesCurrentlyInCreation缓存中)
						beforePrototypeCreation(beanName);
						try {
							return createBean(beanName, mbd, args);
						}
						finally {
							// 创建实例后的操作(将创建完的beanName从prototypesCurrentlyInCreation缓存中移除)
							afterPrototypeCreation(beanName);
						}
					});
					// 返回beanName对应的实例对象
					bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
				}
				catch (IllegalStateException ex) {
					throw new BeanCreationException(beanName,
							"Scope '" + scopeName + "' is not active for the current thread; consider " +
							"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
							ex);
				}
			}
		}
		catch (BeansException ex) {
			cleanupAfterBeanCreationFailure(beanName);
			throw ex;
		}
	}
	// ...... 省略
	return (T) bean;
}
  • transformedBeanName() 是为了获取 bean 真正的名称,它会去掉 name 前面的 &

  • 而 getSingleton() 是从父类 DefaultSingletonBeanRegistry 的 getSingleton() 方法中的 singletonObjects 一级缓存中取的这个 bean 的实例

    image-20221018190145373

回到 doGetBean() 方法中,拿到 sharedInstance 后,后面的一大堆操作做了单例、多例等判断,最终会走到 getObjectForBeanInstance(),关键部分就在这个方法中,进入方法代码

2.1.1.getObjectForBeanInstance()

protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

	// 如果 name 不为空且以 & 开头
	if (BeanFactoryUtils.isFactoryDereference(name)) {
		// beanInstance 属于 NullBean 或其子类的实例
		if (beanInstance instanceof NullBean) {
			return beanInstance;
		}
		if (!(beanInstance instanceof FactoryBean)) {
			throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
		}
	}
	// beanInstance 不是属于 FactoryBean 或其子类的实例,或 name 不为空且以 & 开头
	if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
		return beanInstance;
	}
	
	// 只有当 name 不为空且以 & 开头,并且 beanInstance 属于 FactoryBean 或其子类的实例时,才会执行下面
	Object object = null;
	if (mbd == null) {
		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());
		// 关键部分,如下
		object = getObjectFromFactoryBean(factory, beanName, !synthetic);
	}
	return object;
}
2.1.1.1.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) {
				// 关键部分
				object = doGetObjectFromFactoryBean(factory, beanName);
				Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
				if (alreadyThere != null) {
					object = alreadyThere;
				}
				else {
					if (shouldPostProcess) {
						if (isSingletonCurrentlyInCreation(beanName)) {						
							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)) {
						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;
	}
}
2.1.1.1.1.doGetObjectFromFactoryBean()
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
		throws BeanCreationException {

	Object object;
	try {
		if (System.getSecurityManager() != null) {
			AccessControlContext acc = getAccessControlContext();
			try {
				object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
			}
			catch (PrivilegedActionException pae) {
				throw pae.getException();
			}
		}
		else {
			// 关键代码
			object = factory.getObject();
		}
	}
	catch (FactoryBeanNotInitializedException ex) {
		throw new BeanCurrentlyInCreationException(beanName, ex.toString());
	}
	catch (Throwable ex) {
		throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
	}

	if (object == null) {
		if (isSingletonCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(
					beanName, "FactoryBean which is currently in creation returned null from getObject");
		}
		object = new NullBean();
	}
	return object;
}
  • 关键代码 object = factory.getObject() 这个 factory 就是我们传入的 beanInstance 实例。绕了这么一大圈,getBean() 方法返回的居然是我们实现 FactoryBean 接口定义的 getObject() 方法

3.总结

3.1.FactoryBean接口的作用

一般情况下,Spring 通过反射机制利用的 class 属性指定实现类实例化 Bean,在某些情况下,实例化 Bean 过程比较复杂,如果按照传统的方式,则需要在中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。 Spring 为此提供了一个 org.springframework.bean.factory.FactoryBean 的工厂类接口,用户可以通过实现该接口定制实例化 Bean 的逻辑。FactoryBean 接口对于 Spring 框架来说占用重要的地位,Spring 自身就提供了 70 多个 FactoryBean 的实现。它们隐藏了实例化一些复杂 Bean 的细节,给上层应用带来了便利

FactoryBean 是一个能生产或修饰对象生成的工厂 Bean。一个 Bean 如果实现了 FactoryBean 接口,那么根据该 Bean 的名称获取到的实际上是 getObject() 返回的对象,而不是这个 Bean 自身实例,如果要获取这个 Bean 自身实例,那么需要在名称前面加上 & 符号

4.测试验证

下面通过代码测试验证上面的流程,先定义一个 Bean 实现 FactoryBean 接口

@Component
public class MyBean implements FactoryBean {

    private String message;
    
    public MyBean() {
        this.message = "通过构造方法初始化实例";
    }
    
    @Override
    public Object getObject() throws Exception {
        MyBean myBean = new MyBean();
        myBean.message = "通过FactoryBean.getObject()创建实例";
        // 这里并不一定要返回MyBean自身的实例,可以是其他任何对象的实例
        return myBean;
    }
    
    @Override
    public Class<?> getObjectType() {
        return MyBean.class;
    }
    
    public String getMessage() {
        return message;
    }
}

MyBean 实现了 FactoryBean 接口的两个方法,getObject() 是可以返回任何对象的实例的,这里测试就返回 MyBean 自身实例,且返回前给 message 字段赋值。同时在构造方法中也为 message 赋值。然后测试代码中先通过名称获取 Bean 实例,打印 message 的内容,再通过 &+名称 获取实例并打印 message 内容

@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestApplication.class)
public class FactoryBeanTest {

    @Autowired
    private ApplicationContext context;
    
    @Test
    public void test() {
        MyBean myBean1 = (MyBean) context.getBean("myBean");
        System.out.println("myBean1 = " + myBean1.getMessage());
        MyBean myBean2 = (MyBean) context.getBean("&myBean");
        System.out.println("myBean2 = " + myBean2.getMessage());
        System.out.println("myBean1.equals(myBean2) = " + myBean1.equals(myBean2));
    }
}

结果如下

myBean1 = 通过FactoryBean.getObject()初始化实例
myBean2 = 通过构造方法初始化实例
myBean1.equals(myBean2) = false
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值