spring之BeanFactory源码解析

FactoryBean是什么

FactoryBean是spring源码中一种特殊的bean,就如同这个Bean的中文翻译一样,是一个工厂Bean,是用来生成Bean的工厂

可以用来干什么

假如我们不希望spring帮助我们去New一个对象,但是又希望生成的对象能交给spring进行管理,那么我们可以去实现这个FactoryBean接口,重写其中的getObject方法这样就可以根据自己的逻辑去生成一个Bean对象

源码解析

FactoryBean

public interface FactoryBean<T> {

	@Nullable
	T getObject() throws Exception;
	
	@Nullable
	Class<?> getObjectType();
	
	default boolean isSingleton() {
		return true;
	}
}

可以看到FactoryBean中主要有三个方法,着三个方法也就是我们去实现一个FactoryBean需要去实现的方法
getObject():用户可以在这里生产自己的Bean,然后由FactoryBean进行生产
getObjectType():生产对象的类型
isSingleton():生产的对象是否为单例

首先要清除FactoryBean,本身也是一个Bean,当我们去实现FactoryBean这个接口实现自己的FactoryBean之后,如果想让这个Bean 生效,也需要加上@Component这个注解,将这个Bean注册到spring 的容器,所以在spring启动的初期,这个FactoryBean是被当成一个普通的Bean加载到spring容器的,接下来介绍源码具体的实现

applicationContext.getBean("factoryBeanName");

例如使用getBean这个方法来获取FactoryBean生产的对象,根据方法的调用会进入到doGetBean

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;
		......

首先doGetBean做的处理就是transformedBeanName,这里进行名字的处理原因有很多,分为三种情况
1.我们传入的本来就是一个首字母小写的BeanName,这种情况其实不会进行处理,传入的字符和处理后的字符是相同的
2.传入的是FactoyBean的名字,那么我们会返回FactoayBean对应的首字母小写的名字
3.传入的是“&“加上FactoyBean的名字,那么我们返回的也是FactoryBean对应的首字母小写的名字
也就是说在这里spring会进行统一的处理,最后返回的都是类名对应首字母小写的名字

		Object sharedInstance = getSingleton(beanName);  
		if (sharedInstance != null && args == null) {
			//日志信息省略...
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

尝试从单例池里面获取,这里就印证了前面说的话,FactoryBean在spring容器总也是作为一个普通bean来存储的,所以要获取也是同普通的bean一样从单例池里面进行获取,这里为了方便分析,假设我们自己实现的FactoryBean没有设置为懒加载,那么在这里是可以直接获取到的
再然后就会进入 getObjectForBeanInstance这个方法
在这个方法里面会做一个判断如下

public static boolean isFactoryDereference(@Nullable String name) {
		return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
}

就是判断这个传入进来的名字是不是以BeanFactory.FACTORY_BEAN_PREFIX开始,这个符号就是“&”
如果是以这个符号开始那么就直接返回了,因为以”&“这个符号开始的话,我们要取出来的就是FactoryBean本身了
而这个bean在spring容器初始化的时候已经实例化了,所以我们通过前面的单例池就可以直接取出,这里也就能直接进行返回了

那么如果是FactoryBean但是不以“&”开头又会做什么处理呢?

	object = getCachedObjectForFactoryBean(beanName);

spring会先在容器里面尝试去拿,这里是从一个叫做factoryBeanObjectCache的map里面去拿
这个map key:beanName value:getObject返回的方法
但是第一次拿肯定是拿不到的,因为bean的生命周期中是不涉及直接去调用FactoryBean的getObject方法的
那么紧接着,我们想获取到这个getObject返回出来的对象,那么我们只能先去创建,并加入缓存了
那么这样是不是可以理解为FactoryBean的getObject返回的实例是懒加载的呢?

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());
			// 调用getObject方法得到对象并放入factoryBeanObjectCache中
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;

在这个过程中其实还有一个比较重要的操作getMergedLocalBeanDefinition,这个在后面进行介绍
先介绍最重要的去getObject的方法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) {
					// 调用getObject方法得到一个对象
					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)) {
								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;
		}
	}

在这里面首先通过调用我们重写的isSingleton方法判断是不是一个单例Bean,然后加锁,但是加锁之后,
Object object = this.factoryBeanObjectCache.get(beanName);
又从缓存里面拿了一遍,这里其实是可以看成双端检索,如果说缓存里面拿不到就会真正的去拿getObject返回的Bean了
取得这个Bean之后机会将这个Bean返回,至此也就得到了这个Bean
以上就是FactoryBean在spring中实现的原理和流程

这里还有一点需要注意,即使时单例的FactoryBean也不会放入单例池,而是专门有一个factoryBeanObjectCache去存储这类Bean

补充1

还有没有和FactoryBean一样,能通过new对象的方式返回一个bean呢?
当然时有的,@Bean就可以达成这个效果,但是@Bean不如FactoryBean强大,因为FactoryBean在使用的时候还可以去实现其他的接口,例如XXXAware,或者是后置处理器,又或者是生命周期接口等等等,所以相比@Bean,FactoryBean能做的事情更多!

补充2

上面说过继承自FactoryBean接口,从FactoryBean的getObject方法里面返回出来的对象是懒加载的,那么有没有非懒加载的getObject?
这个也是有的但是对应要实现的是 SmartFactoryBean
如下是 Spring在实例化Bean的 preInstantiateSingletons() 方法中的一段源码:

if (bean instanceof FactoryBean) {
	final FactoryBean<?> factory = (FactoryBean<?>) bean;
	boolean isEagerInit;
	// eager:急切的意思,立马初始化
	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) {
		// 根据beanName去生成FactoryBean中所生成的Bean对象
		getBean(beanName);
	}
}

判断传过来的beanName是不是一个FactoryBean,如果是FactoryBean,还会去判断这个FactoryBean是不是一个
SmartFactoryBean,并且还会返回一个EagerInit 的属性
这个属性就与SmartFactoryBean 相关,SmartFactoryBean是FactoryBean的子类,在这个子类中多提供了一个isEagerInit()
表示当前FactoryBean的getObject()返回出来的对象是不是懒加载,如果不是懒加载就会直接进行创建

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值