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为什么要注入到容器中?
- 因为Spring通过控制反转的思想将Bean对象的管理权从开发者转移到Spring中,解放开发者对于Bean对象的创建和销毁,只关心实际的业务开发逻辑即可,提高开发者的开发效率。
- 另一方面的两个容器则是Spring用于解决实际开发中Bean循环依赖问题增加的两个容器,三个容器共同使用保证开发者在使用Spring过程中的稳定。
以上就是自己对于Spring中容器的理解,如有理解问题欢迎评论、私信指正!共同进步!