Spring容器源码分析

281 阅读3分钟

1. 问题

前面了解了Spring的Bean的注入,那么自然就会存在几个疑问:

  • Bean注入到什么容器中?
  • Bean为什么要注入到容器中?

根据这两个问题来梳理Spring中容器的理解。

2. Bean注入到什么容器中

Spring中Bean注入的容器主要有三个,也是在前面说过的三级缓存的三个容器,分别为:

  • singletonObjects(一级缓存)

  • earlySingletonObjects(二级缓存)

  • singletonFactories(三级缓存)

这也是Spring解决Bean循环依赖所提出的三级缓存的实现。在三个容器中主要的使用是一级缓存,可以理解为平时开发过程中getBean的操作基本都是从一级缓存中获取的,从一级缓存中获取到的Bean也都是实例化成功的Bean。

三个容器的源码如下:

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
	//一级容器
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
	//三级容器
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
	//二级容器
	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

}

那么三个容器又是如何实现注入的呢?

2.1 singletonObjects容器

一级容器的注入则是在整个Bean都具备所有的实例化后才进行注入,因此可以理解为注入到该容器中的Bean都是可以随时取用的,也就是前面提高的开发过程中的getBean实际都是从该容器中获取的。

对于该容器的注入的实现源码如下:

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
	//执行最终Bean注入的逻辑
	protected void addSingleton(String beanName, Object singletonObject) {
		synchronized (this.singletonObjects) {
			//将Bean注入到一级容器中
			this.singletonObjects.put(beanName, singletonObject);
			this.singletonFactories.remove(beanName);
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.add(beanName);
		}
	}

}

可以看到该容器的注入是在整个Bean注入链路的最后实现的,因此此处的Bean具备了可以实际使用的功能,因此在此可执行注入可以保证该容器的最终可用性。

2.2 earlySingletonObjects容器

二级容器的作用中的Bean并不具备实际的使用,该容器主要的作用是用于服务启动过程中获取Bean,将Bean进行提前暴露存储到该容器中。

并且该容器的Bean并不是完整的Bean,注入到该容器的Bean并没有完整的实例化,此处的Bean中的属性并没有填充,只是最原始的Bean对象,并且该容器的主要作用就是用于解决循环依赖的问题。

该二级容器的注入的实现源码如下:

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {

	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		//先从一级容器中获取Bean
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				//再从二级容器中获取
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					//最后从三级容器中获取
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						//注入二级容器
						this.earlySingletonObjects.put(beanName, singletonObject);
						//从三级容器中溢移除
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}
}

2.3 singletonFactories容器

最后就是三级容器,该容器跟前两个容器又有比较大的区别,因此该容器中存储的并不是Bean对象本身,而是Bean对象的工厂对象,也就是对Bean做了封装的对象ObjectFactory

该容器的实现也是为了解决循环依赖的问题。

该容器的实现源码如下:

@FunctionalInterface
public interface ObjectFactory<T> {


	T getObject() throws BeansException;

}
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {

	protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(singletonFactory, "Singleton factory must not be null");
		synchronized (this.singletonObjects) {
			if (!this.singletonObjects.containsKey(beanName)) {
				//三级容器的注入
				this.singletonFactories.put(beanName, singletonFactory);
				this.earlySingletonObjects.remove(beanName);
				this.registeredSingletons.add(beanName);
			}
		}
	}

}
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
		implements AutowireCapableBeanFactory {

	//创建Bean的实现
	protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			//创建Bean实例
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}
		//省略部分代码

		//判断是否需要将Bean进行提前暴露
		//提前缓存Bean能够解决循环引用问题
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		//如果需要提前暴露,则将该beanFactory写入三级容器中
		if (earlySingletonExposure) {
			if (logger.isTraceEnabled()) {
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			//======将BeanFactory写入三级容器的调用=========
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			//填充Bean属性的逻辑
			populateBean(beanName, mbd, instanceWrapper);
			//实例化Bean的逻辑:比如执行Bean的初始化方法(实现了xxxAware接口的实现类)
			//和BeanPostProcessor的前置和后置处理
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		//省略部分代码
		return exposedObject;
	}
}

3. Bean为什么要注入到容器中

前面讲解了三个容器在Spring中是如何注入的,那么再回答另一个问题,为什么要将Bean注入到容器中。

对于这个问题就涉及到Spring的核心思想:IOC,即控制反转,Spring将Bean注入到容器中就是为了将Bean的控制权从开发者手中转移到Spring容器中,开发者不需要关心Bean对象的创建,只要按照Spring的规范使用对象即可,Bean对象的创建和销毁都由Spring来管理,这就是控制反转。

那么对于这个问题的答案就可以回答了:Bean为什么要注入到容器中?

  1. 因为Spring通过控制反转的思想将Bean对象的管理权从开发者转移到Spring中,解放开发者对于Bean对象的创建和销毁,只关心实际的业务开发逻辑即可,提高开发者的开发效率。
  2. 另一方面的两个容器则是Spring用于解决实际开发中Bean循环依赖问题增加的两个容器,三个容器共同使用保证开发者在使用Spring过程中的稳定。

以上就是自己对于Spring中容器的理解,如有理解问题欢迎评论、私信指正!共同进步!