【源码Spring系列】——彻底搞懂BeanFactory和FactoryBean不同

前提

        BeanFactory和FactoryBean在学习Spring源码之前总是傻傻分不清,搞不懂两者的区别,这次学习Spring源码的过程,感觉自己开窍了,整理下相关点,希望可以帮助需要的朋友。

几个概念要分清楚

何为Bean?

        类比的方式 Java  Object 等同于 Spring Bean。Bean就是Spring中管理的对象。所以无论是BeanFactory还是FactoryBean,都是为了操作Spring中的对象。之后在怎么区分两者呢,Java中常讲的命名要规范,那Spring源码命名绝对是典范,BeanFactory—— bean工厂,FactoryBean——工厂bean,两者英译汉的侧重点,一个是工厂,另一个bean而已。

 BeanFactory

         BeanFactory定义了 IOC 容器的最基本形式,并提供了 IOC 容器应遵守的的最基本的接口,也就是 Spring IOC 所遵守的最底层和最基本的编程规范。在  Spring 代码中, BeanFactory 只是个接口,并不是 IOC 容器的具体实现,但是 Spring 容器给出了很多种实现,如 DefaultListableBeanFactory 、XmlBeanFactory等。

          在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的,同样Factory也是需要接受BeanFactory的管理。

FactoryBean

         FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似 、 ApplicationContext 等,都是附加了某种功能的实现。一个Bean如果实现了FactoryBean接口,那么根据该Bean的名称获取到的实际上是getObject()返回的对象,而不是这个Bean自身实例,如果要获取这个Bean自身实例,那么需要在名称前面加上'&'符号。下方简单附一个FactoryBean的使用方式

@Component
public class MyFactoryBean implements FactoryBean {
   @Override
   public Object getObject() throws Exception {
      return new User();
   }

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

 System.out.println(context.getBean("myFactroyBean")); //User
 System.out.println(context.getBean("&myFactroyBean")); //MyFactroyBean

       上篇文章说每一个bean都一个对应的BeanDefinition,其中定义bean的相关属性,再加上注册器就可以实现Bean的创建,那么为什么还要有一个FactoryBean同样可以用来创建Bean呢?

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

       FactoryBean就相当于Spring提供外界的一个暴露点,通过它完整复杂Bean的实例化。

FactoryBean实现原理

// org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
         //获取bean真正的名称
		final String beanName = transformedBeanName(name);
		Object bean;

		// Eagerly check singleton cache for manually registered singletons.
        //从单例对象池拿到bean实例
		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 + "'");
				}
			}
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}
// 以下逻辑省略,如有需要自行查看源码
}

transformedBeanName(name)是为了获取Bean真正的名称,它会去掉name前面的'&',而getSingleton(beanName)是从父类容器singletonObjects中取的这个Bean的实例。在Spring中还有很多这样的容器,比如DefaultListableBeanFactory中的beanDefinitionMap,它就是的IOC容器真正保存Bean的地方,它是一个CurrentHashMap。类似的还有FactoryBeanRegistrySupport中的factoryBeanObjectCache等。

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

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.
        //判断name是否不为空且以&开头
		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.
        //判断的是beanInstance是否属于FactoryBean或其子类的实例
		if (!(beanInstance instanceof FactoryBean)) {
			return beanInstance;
		}

		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());
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}

上述逻辑关键点 beanInstance instanceof FactoryBeanBeanFactoryUtils.isFactoryDereference(name)。如果beanInstance不属于FactoryBean或其子类的实例,或者name是以&开头就直接返回实例对象beanInstance,否则进入到if分支中。分支中重点

object = getObjectFromFactoryBean(factory, beanName, !synthetic);

具体逻辑如下

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);
					// Only post-process and store if not put there already during getObject() call above
					// (e.g. 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);
							}
						}
						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;
		}
	}

这段逻辑中大概的意思就是目的是从factoryBeanObjectCache中获得FactoryBean,无论是否能拿到if else中逻辑都会执行object = doGetObjectFromFactoryBean(factory, beanName);

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);
		}

关键点

object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);

这个factory就是我们传入的beanInstance实例。绕了这么一大圈,getBean方法返回的居然是我们实现FactoryBean接口定义的getObject方法。这刚好和上方的描述相呼应了。

额外解释下 factoryBeanObjectCache 是什么?

/** Cache of singleton objects created by FactoryBeans: FactoryBean name to object. */
	private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);

通过这个定义和源码中注释可以得知 factoryBeanObjectCache中存储的FactoryBean,在getObjectForBeanInstance()中有段逻辑

object = getCachedObjectForFactoryBean(beanName);
/**
	 * Obtain an object to expose from the given FactoryBean, if available
	 * in cached form. Quick check for minimal synchronization.
	 * @param beanName the name of the bean
	 * @return the object obtained from the FactoryBean,
	 * or {@code null} if not available
	 */
	@Nullable
	protected Object getCachedObjectForFactoryBean(String beanName) {
		return this.factoryBeanObjectCache.get(beanName);
	}

如果以&开头就直接返回实例对象beanInstance,beanInstance则是从factoryBeanObjectCache中获取的,由此也知道FactoryBean本身并不存储到单例对象池中,获取本身为需要加&用于区分。

       主要介绍BeanFactory和FactoryBean在命名上区分,在Spring中不同的作用,以及FactoryBean的实验原理。FactoryBean在Spring中存在的意义为了解决配置方式装配bean灵活性是受限的问题,通过编码得到一个简单的方案。

      关于FactoryBean的使用场景,特别像代理模式的实现方案,借助FactoryBean创建代理对象在原对象基础上处理其他内容。那么代理对象和工厂模式,装饰模式又有什么不同呢?之后的文章中慢慢解答,请关注哈!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mandy_i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值