Spring 源码分析衍生篇一:FactoryBean介绍

一、前言

本文是 Spring源码分析:bean的加载过程 的衍生文章。主要是因为本人菜鸡,在分析源码的过程中还有一些其他的内容不理解,故开设衍生篇来完善内容以学习。


关于 FactoryBean 在源码中的设计,可以参考上面提及的正文bean的加载过程内容。在getObjectForBeanInstance 方法中有详细的分析。

二、简介

一般情况下,Spring通过反射机制利用bean的class属性指定实现类来实例化bean。但是在某些情况下,实例化bean 的过程比较复杂,在XML配置下如果按照传统的编码方式,则需要进行大量配置,灵活性受限,这时候Spring 提供了一个 org.springframework.beans.factory.FactoryBean 的工厂类接口。可以通过该接口定制实例化bean 的逻辑。
除此之外,FactoryBean在Spring框架中都占有很重要的地位,Spring自身就提供了非常多的FactoryBean的实现。


首先我们来看看 FactoryBean 接口的定义。方法比较简单,见名知意。

public interface FactoryBean<T> {
    
    
	// 属性名
	String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

	// 获取bean实例,实例化bean 的逻辑就在这里实现
	@Nullable
	T getObject() throws Exception;
	// 获取bean类型
	@Nullable
	Class<?> getObjectType();
	// 是否是单例
	default boolean isSingleton() {
    
    
		return true;
	}

}
  • T getObject() : 返回由FactoryBean创建的bean实例,如果isSingleton() 返回true,则会将该实例方法Spring容器的单例缓冲池中
  • Class<?> getObjectType() : 返回由FactoryBean 创建的bean 的类型
  • boolean isSingleton() : 返回由FactoryBean 创建的bean实例的作用域是singleton还是Prototype。

三、正文

下面举个简单的例子进一步说明FactoryBean 的用法。

@Component
public class DemoFactoryBean implements FactoryBean<DemoBean> {
    
    
    @Override
    public DemoBean getObject() throws Exception {
    
    
        System.out.println("DemoFactoryBean.getObject");
        return new DemoBean();
    }

    @Override
    public Class<?> getObjectType() {
    
    
        return DemoBean.class;
    }
}
@SpringBootApplication
public class BeanInitDemoApplication {
    
    
    public static void main(String[] args) {
    
    
        ConfigurableApplicationContext run = SpringApplication.run(BeanInitDemoApplication.class, args);
        Object demoFactoryBean = run.getBean("demoFactoryBean");
        Object bean = run.getBean("&demoFactoryBean");
        System.out.println("BeanInitDemoApplication.main");
    }

}

如上一个简单的例子,调用结果如下,可以看到:我们这里直接调用 run.getBean("demoFactoryBean"); 返回的并不是 DemoFactoryBean ,而是DemoBean 。而我们使用 run.getBean("&demoFactoryBean"); 返回的结果却是DemoFactoryBean
在这里插入图片描述


实际上,当调用 run.getBean("demoFactoryBean"); 时,Spring通过反射会发现 DemoFactoryBean 实现了FactoryBean接口,则会直接调用 其getObject() 方法,并将方法的返回值注入到Spring容器中。而如果想要获得DemoFactoryBean 实例,则需要在 beanName前加上 & ,即 run.getBean("&demoFactoryBean");

四、源码解读

比较完成的源码分析可以看 bean的加载过程
这里仅仅介绍一下 FactoryBean 的处理过程,所以内容覆盖可能不够全面。


对于 FactoryBean的处理在 AbstractBeanFactory#getObjectForBeanInstance 方法中完成

	bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);

代码逻辑大体如下:

  1. 判断是否需要获取 FactoryBean实例。 通过 BeanFactoryUtils.isFactoryDereference(name) 来判断
    判断name 是否以 & 开头。如果是则说明是想获取 FactoryBean 的实例,所以经过简单校验后就直接返回beanInstance。
  2. 经过第一步,现在可以确定,当前bean不是为了获取FactoryBean实现类,那么这个bean还可能是普通bean或者FactoryBean。if (!(beanInstance instanceof FactoryBean)) 判断如果不是FactoryBean则没必要进行下一步处理,直接返回即可。
  3. 这一步可以确定,这里的bean是 FactoryBean类型,并且name 是“beanName”,表明是想获取bean实例,而不是beanFactory实例,则将解析bean的工作委托给 getObjectFromFactoryBean完成。getObjectFromFactoryBean 方法对FactoryBean的解析还是在 中完成。(getObjectFromFactoryBean 这一步调用了ObjectFactory的后置处理器
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 是否是想获取 工厂类(name 以 & 开头) 
		if (BeanFactoryUtils.isFactoryDereference(name)) {
    
    
			if (beanInstance instanceof NullBean) {
    
    
				return beanInstance;
			}
			// 以&开头又不是FactoryBean实现类,则抛出异常
			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.
		// 2. 判断如果beanInstance 不是 FactoryBean,就直接返回
		if (!(beanInstance instanceof FactoryBean)) {
    
    
			return beanInstance;
		}
		// 3. 到这一步就可以确定,当前beanInstance 是FactoryBean,并且需要获取getObject() 的结果
		Object object = null;
		if (mbd != null) {
    
    
			mbd.isFactoryBean = true;
		}
		else {
    
    
			// 尝试从缓存中加载bean
			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.
			// containsBeanDefinition 检测  beanDefinitionMap中也就是所有已经加载的类中检测是否定义beanName
			if (mbd == null && containsBeanDefinition(beanName)) {
    
    
				// 合并父类bean 定义的属性
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			// 4. 这一步中对FactoryBean进行了解析。
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}

getObjectFromFactoryBean 方法中 调用 doGetObjectFromFactoryBean 方法进行了解析。
上面已经说了,因为这里的bean是FactoryBean,且并不是为了获取FactoryBean实例,所以会调用factory.getObject() 方法将得到的bean返回。


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);
					// 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)			
					// 因为是单例模式,所以要保证变量的全局唯一。所以这里如果缓存中已经创建好了bean则替换为已经创建好的bean
					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 {
    
    
								// 调用了ObjectFactory的后置处理器。
								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;
		}
	}

	....
	
	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 {
    
    
				// 直接调用getObject方法。
				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);
		}

		// Do not accept a null value for a FactoryBean that's not fully
		// initialized yet: Many FactoryBeans just return null then.
		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;
	}

以上:内容部分参考
《Spring源码深度解析》
如有侵扰,联系删除。 内容仅用于自我记录学习使用。如有错误,欢迎指正

猜你喜欢

转载自blog.csdn.net/qq_36882793/article/details/105748071