美文网首页
spring容器之不同scope bean的创建

spring容器之不同scope bean的创建

作者: 会上树的程序猿 | 来源:发表于2019-07-07 14:32 被阅读0次

关于不同Scope的bean,spring通过不同的策略来处理以及创建过程,在整个过程中我们知道默认为Singleton,当然还有prototype和request等等,首先我们来看spring对Singleton的处理过程:

 AbstractBeanFactory.java
//单例的情况下
if (mbd.isSingleton()) {
//从缓存(singletonObjects)中去拿
sharedInstance = getSingleton(beanName, () -> {
    try {
        return createBean(beanName, mbd, args);
            }
            catch (BeansException ex) {
            //最后从缓存中移除对应的实例原因有:
            //1.每当有bean在创建时,允许循环参考来解析对应的beanDefinition
            //2.删除临时引用该bean的bean
              destroySingleton(beanName);
                throw ex;
            }
        });

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

方法很明确,当我们合并后rootBeanDefinition是单例的时候,通过调用#getSingleton(String beanName, ObjectFactory<?> singletonFactory)来实现,关于spring获取Singleton bean的过程请参考spring容器之单例bean的获取这篇文章,若如果在缓存中没有了spring又是如何处理的呢?接着看:

  DefaultSingletonBeanRegistry.java
/**
 * Return the (raw) singleton object registered under the given name,
 * creating and registering a new one if none registered yet.
 * @param beanName the name of the bean
 * @param singletonFactory the ObjectFactory to lazily create the singleton
 * with, if necessary
 * @return the registered singleton object
 */
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "Bean name must not be null");
    //考虑到并发情况,锁住全局变量
    synchronized (this.singletonObjects) {
        //1.通过参数beanName从singletonObjects缓存中获取
        Object singletonObject = this.singletonObjects.get(beanName);
        //如果没获取到
        if (singletonObject == null) {
            //1.1. 判断当前bean是否是销毁状态
            if (this.singletonsCurrentlyInDestruction) {
                throw new BeanCreationNotAllowedException(beanName,
                        "Singleton bean creation not allowed while singletons of this factory are in destruction " +
                        "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
            }
            //2.单例bean创建之前的检验
            beforeSingletonCreation(beanName);
            boolean newSingleton = false;
            //2.1.异常集合的初始化过程
            //suppressedExceptions用来保存单例bean获取过程中的不必要的异常
            boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet<>();
            }
            try {
                //3.初始化singletonObject实例
                //该过程实际上调用的createBean()方法来做处理
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            }
            catch (IllegalStateException ex) {
                // Has the singleton object implicitly appeared in the meantime ->
                // if yes, proceed with it since the exception indicates that state.
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                    throw ex;
                }
            }
            catch (BeanCreationException ex) {
                if (recordSuppressedExceptions) {
                    for (Exception suppressedException : this.suppressedExceptions) {
                        ex.addRelatedCause(suppressedException);
                    }
                }
                throw ex;
            }
            finally {
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = null;
                }
                //单例bean创建之后的处理过程
                afterSingletonCreation(beanName);
            }
            //将创建之后的bean保存到singletonObjects中
            if (newSingleton) {
                addSingleton(beanName, singletonObject);
            }
        }
        return singletonObject;
    }
}

这就是当缓存中没有时,spring的处理过程,还是尝试着去从缓存中获取,如果没有获取到,通过ObjectFactory#getObject()进行bean实例的初始化,然后在保存到singletonObjects缓存中,在整个的过程中,实际上我们发现并没有看到创建bean的过程,只是做了一些创建bean前提的准备工作,我们来看一下都做了些什么:

  • 首先在1处尝试着去获取,如果有的话直接返回该bean的instance即可
  • 如果在缓存没获取到,开始进行bean的加载过程
  • 在2处我们可以看到的是首先在加载bean之前的检验,在之前的文章单例bean的获取过程说过了,这里就不多说了.
  • 检验之后首先是对异常集合的初始化过程
private Set<Exception> suppressedExceptions;
//2.1.异常集合的初始化过程
  //suppressedExceptions用来保存单例bean获取过程中的不必要的异常
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
      this.suppressedExceptions = new LinkedHashSet<>();
    }
  • 前提的过程完成后,我们可以看到在3处是真正的初始化bean的过程,可以看到的是通过我们的参数ObjectFactory#getObject()来完成,如何实现我们后续说.
  • 在我们bean实例初始化完成后,进行后续的扫尾工作,对我们实例化的bean进行不能重复创建的标记处理,下次获取直接获取即可,关于afterSingletonCreation(String beanName)详细讲解我们在单例bean获取的过程中详细的说过了,这里不再重复了.
  • 最后将我们实例化的bean保存在singletonObjects缓存中
/**存放单例bean的映射集合map*/
//对应关系: bean  name -----> bean  instance
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/**存放objectFactory的map映射集合*/
//对应关系: bean  name-----------> objectFactory
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/**存放早期单例bean的映射集合*/
//对应关系: bean   name ---------> bean instance
//与singletonObjects不同区别是,如果单例的bean保存到earlySingletonObjects时,如果该bean此时处于创建过程中,可以直接通过getBean()方法获取,也就是提早的暴露该bean,主要是为了解决循环依赖的问题
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/**存放的是当前已经完成注册的bean*/
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
/**
 * 将单例的bean保存到缓存中
 * @param beanName
 * @param singletonObject
 */
protected void addSingleton(String beanName, Object singletonObject) {
    synchronized (this.singletonObjects) {
        //保存到singletonObjects缓存里
        this.singletonObjects.put(beanName, singletonObject);
        //从singletonFactories工厂缓存中移除相应的bean的实例
        this.singletonFactories.remove(beanName);
        //从早期单例缓存中移除对应的bean实例
        this.earlySingletonObjects.remove(beanName);
        //将该bean添加注册表中
        this.registeredSingletons.add(beanName);
    }
}

以上就是缓存中不存在的情况下,spring还是通过#getSingleton(String beanName, ObjectFactory<?> singletonFactory)来完成了单例bean的获取

  • 完成了单例bean的获取之后,紧接着是通过#getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd) 方法来获取我们想要的bean对象,关于该方法的详细过程在之前的[spring容器之从bean的实例中获取对象spring容器之从bean的实例中获取对象
    )详细的讲解了,感兴趣的可以去看看
    #######原型(prototype)模式
AbstractBeanFactory.java
//原型的情况下:
else if (mbd.isPrototype()) {

      Object prototypeInstance = null;
    try {
        beforePrototypeCreation(beanName);
        prototypeInstance = createBean(beanName, mbd, args);
        }
        finally {
                    //创建完bean的处理
                  afterPrototypeCreation(beanName);
        }
        bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}

上面代码就是spring对原型模式的处理过程,很简单,直接调用#createBean()方法创建一个bean即可

  1. 先是判断是否是原型(prototype)
  2. 调用#beforePrototypeCreation(String beanName)方法进行原型创建之前的状态记录
/** Names of beans that are currently in creation. */
private final ThreadLocal<Object> prototypesCurrentlyInCreation =
        new NamedThreadLocal<>("Prototype beans currently in creation");

/**
 * Callback before prototype creation.
 * <p>The default implementation register the prototype as currently in creation.
 * @param beanName the name of the prototype about to be created
 * @see #isPrototypeCurrentlyInCreation
 */
@SuppressWarnings("unchecked")
protected void beforePrototypeCreation(String beanName) {
    //从prototypesCurrentlyInCreation获取当前所有的正在创建的bean
    Object curVal = this.prototypesCurrentlyInCreation.get();
    //没有正在创建的bean,  然后进行保存
    if (curVal == null) {
        this.prototypesCurrentlyInCreation.set(beanName);
    }
    //如果是正在创建的bean是String类型的
    else if (curVal instanceof String) {
        //进行保存操作
        Set<String> beanNameSet = new HashSet<>(2);
        beanNameSet.add((String) curVal);
        beanNameSet.add(beanName);
        this.prototypesCurrentlyInCreation.set(beanNameSet);
    }
    //是set集合的的话
    else {
        Set<String> beanNameSet = (Set<String>) curVal;
        beanNameSet.add(beanName);
    }
}
  1. 状态记录完成之后,接着是调用#createBean(String beanName, RootBeanDefinition mbd, Object[] args)进行bean的创建,关于详细的创建过程后面在学习
    4.bean的创建完成后调用#afterPrototypeCreation(String beanName)进行后置处理操作.
/**
 * Callback after prototype creation.
 * <p>The default implementation marks the prototype as not in creation anymore.
 * @param beanName the name of the prototype that has been created
 * @see #isPrototypeCurrentlyInCreation
 */
@SuppressWarnings("unchecked")
protected void afterPrototypeCreation(String beanName) {
    Object curVal = this.prototypesCurrentlyInCreation.get();
    if (curVal instanceof String) {
        this.prototypesCurrentlyInCreation.remove();
    }
    else if (curVal instanceof Set) {
        Set<String> beanNameSet = (Set<String>) curVal;
        beanNameSet.remove(beanName);
        if (beanNameSet.isEmpty()) {
            this.prototypesCurrentlyInCreation.remove();
        }
    }
}

4.紧接着是通过#getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd) 方法来获取我们想要的bean对象,关于该方法的详细过程在之前的[spring容器之从bean的实例中获取对象spring容器之从bean的实例中获取对象
)详细的讲解了,感兴趣的可以去看看

其它scope
else {
    //获取bean的作用域
    String scopeName = mbd.getScope();
    final Scope scope = this.scopes.get(scopeName);
          if (scope == null) {
                throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                }
                try {
                    Object scopedInstance = scope.get(beanName, () -> {
                        beforePrototypeCreation(beanName);
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        finally {
                            afterPrototypeCreation(beanName);
                        }
                    });
                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                }
                catch (IllegalStateException ex) {
                    throw new BeanCreationException(beanName,
                            "Scope '" + scopeName + "' is not active for the current thread; consider " +
                            "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                            ex);
                }

处理的流程都差不多,只是在获取bean的过程不一样,是通过Scope#get(String name, ObjectFactory<?> objectFactory)方法来实现,代码如下:

SimpleThreadScope.java
private final ThreadLocal<Map<String, Object>> threadScope =
        new NamedThreadLocal<Map<String, Object>>("SimpleThreadScope") {
            @Override
            protected Map<String, Object> initialValue() {
                return new HashMap<>();
            }
        };

public Object get(String name, ObjectFactory<?> objectFactory) {
    //获取scope
    Map<String, Object> scope = this.threadScope.get();
    //获取bean实例
    Object scopedObject = scope.get(name);
    //如果为null的话
    if (scopedObject == null) {
        //调用ObjectFactory的getobject方法获取实例
        scopedObject = objectFactory.getObject();
        //保存操作
        scope.put(name, scopedObject);
    }
    return scopedObject;
}

该方法位于org.springframework.beans.factory.config.Scope 接口,在该接口中还有很多方法,感兴趣的可以自己去看看

总结

本篇文章主要是针对于不同作用域的bean进行处理的过程,其实质上都很类似,上面说的也很清楚了,这里就不啰嗦了

相关文章

网友评论

      本文标题:spring容器之不同scope bean的创建

      本文链接:https://www.haomeiwen.com/subject/mfzphctx.html