美文网首页spring cloud基础知识点
Spring - BeanFactory 之 Singleton

Spring - BeanFactory 之 Singleton

作者: 剑戈2 | 来源:发表于2019-02-15 13:10 被阅读0次

    Singleton 单例注册


    简介

    我们知道Spring容器的 Bean 可以是单例 (把 scope 配置为 singleton 或者不设置 scope,即默认是单例),这些单例的 Bean 被初始化之后就被Spring注册到BeanFactory管理了起来,方便下次直接使用。除了配置的单例Bean,我们还可以调用BeanFactory的Bean直接注册一个单例Bean。

    SingletonBeanRegistry

    SingletonBeanRegistry是BeanFactory默认实现DefaultListableBeanFactory实现的接口之一。这个接口主要提供了一些单例注册、获取等单例相关的方法。

    public interface SingletonBeanRegistry {
    
        void registerSingleton(String beanName, Object singletonObject);
    
        Object getSingleton(String beanName);
    
        boolean containsSingleton(String beanName);
    
        String[] getSingletonNames();
    
        int getSingletonCount();
    
        Object getSingletonMutex();
    
    }
    

    手动注册单例

    前面提到Spring管理着手动注册以及scope配置为singleton的单例Bean注册。这两种Bean的注册方式是不同的。我们先来看手工注册。

    通过调用registerSingleton(String beanName, Object singletonObject)这个方法注册的Bean就是手动注册的Bean。

    例子:

    @Test
    public void test(){
        ClassPathXmlApplicationContext appContext =
                new ClassPathXmlApplicationContext("classpath:app-context.xml");
        Object object = new Object();
        appContext.getBeanFactory().registerSingleton("object",object);
        System.out.println(object == appContext.getBean("object"));
    }
    

    打印的结果为true,证明可以拿到注册进去的Bean。

    DefaultSingletonBeanRegistry(SingletonBeanRegistry默认实现)源码:

    @Override
    public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
      Assert.notNull(beanName, "Bean name must not be null");
      Assert.notNull(singletonObject, "Singleton object must not be null");
      synchronized (this.singletonObjects) {
        Object oldObject = this.singletonObjects.get(beanName);
        if (oldObject != null) {
          throw new IllegalStateException("Could not register object [" + singletonObject +
              "] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
        }
        addSingleton(beanName, singletonObject);
      }
    }
    
    protected void addSingleton(String beanName, Object singletonObject) {
      synchronized (this.singletonObjects) {
        this.singletonObjects.put(beanName, singletonObject);
        this.singletonFactories.remove(beanName);
        this.earlySingletonObjects.remove(beanName);
        this.registeredSingletons.add(beanName);
      }
    }
    

    代码比较简单,忽略一些校验以及this.singletonFactories.remove(beanName);,this.earlySingletonObjects.remove(beanName);(这两个变量主要是为配置的bean服务的),这两句remove代码,可以看到就是往singletonObjects添加了一个 beanName -> singletonObject, 以及往 registeredSingletons 添加了注册进来的beanName。

    singletonObjects就是管理所有单例bean的一个map。

    自动注册的单例 (配置scope为singleton的bean)

    自动注册,也就是配置的Singleton Bean的注册要比手动注册的复杂得多。原因是,自动注册需要解决循环依赖的问题。

    循环引用

    spring在把Bean创建之后需要给Bean注入参数,假如 A 依赖了 B,那创建 A 的时候就是在 spring 容器里面查找 B,假如这个时候 B 也还没创建那就会创建 B。如果 B 又依赖了 A ,那就会有循环依赖的问题。

    A -> B -> A

    earlySingletonObjects和singletonFactories

    为了解决循环依赖的问题, DefaultSingletonBeanRegistry 中用了 earlySingletonObjectssingletonFactories这两个map来解决这个问题。

    earlySingletonObjects中的 early 指的是new 出来但是还没注入参数的Bean,而earlySingletonObjects管理的正是这种Bean。在上面的源码中,addSingleton的方法。在添加单例之后就移除了earlySingletonObjects中相同beanName的bean,因为已经有了注入好的Bean,就不需要'early'的了。

    singletonFactories spring不会直接创建bean,而是把创建bean的方法(createBean)封装成factory保存在singletonFactories里。

    getSingleton源码

    spring通过getSingleton的这几个方法实现注册配置的bean并解决循环依赖问题。这几个方法有一个比较复杂的调用流程,我们先看这几个方法大概做了些什么,什么我们再通过调用流程深入了解这些方法的功用。

    @Override
    @Nullable
    public Object getSingleton(String beanName) {
        return getSingleton(beanName, true);
    }
    
    @Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName);
        //  判断singletonObjects是否存在要找bean,这个方法大部分情况都会在这里结束,后面的代码只有在存在循环引用才会调用。
        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;
    }
    
    isSingletonCurrentlyInCreation

    第二行代码:isSingletonCurrentlyInCreation(beanName)

    public boolean isSingletonCurrentlyInCreation(String beanName) {
        return this.singletonsCurrentlyInCreation.contains(beanName);
    }
    

    isSingletonCurrentlyInCreation的作用判断这个beanName是不是正在创建,也就是判断是不是循环依赖了。

    举个例子假如 A依赖了B,B又依赖了A (A -> B -> A)。创建 A 时,会先把 A 的beanName添加到 singletonsCurrentlyInCreation这个set里面,然后再去查找B,发现B还没创建就去创建B,同样创建B也会添加到singletonsCurrentlyInCreation,再去查找依赖A,这个时候isSingletonCurrentlyInCreation就会返回true,也就是循环依赖了。

    这个方法依次会从singletonObjects,earlySingletonObjects,singletonFactories查找bean,关于具体什么时候,bean会在那个地方,后面调用流程会有介绍。

    getSingleton(String beanName, ObjectFactory<?> singletonFactory)
    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        synchronized (this.singletonObjects) {
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
                beforeSingletonCreation(beanName);
                boolean newSingleton = false;
                boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = new LinkedHashSet<>();
                }
                try {
                    singletonObject = singletonFactory.getObject();
                    newSingleton = true;
                } catch (IllegalStateException ex) {
                    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;
                    }
                    afterSingletonCreation(beanName);
                }
                if (newSingleton) {
                    addSingleton(beanName, singletonObject);
                }
            }
            return singletonObject;
        }
    }
    
    protected void beforeSingletonCreation(String beanName) {
        if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }
    }
    
    protected void afterSingletonCreation(String beanName) {
        if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
            throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
        }
    }
    

    getSingleton(String beanName, ObjectFactory<?> singletonFactory),这个方法是getSingleton另一个重载方法,在创建之前把beanName放到singletonsCurrentlyInCreation,再通过调用传入的singletonFactory getObject创建bean,在创建之后再把singletonsCurrentlyInCreation移除,最后再把创建的bean注册到singletonObjects。

    这个方法虽然叫getSingleton但实际上主要功能是创建bean再把bean注册。

    调用流程

    假设A依赖了B,B依赖了A,我们分析一下spring是如何调用这几个方法解决依赖循环的问题的,其中加粗的方法是我们前面介绍过的方法,其他方法涉及太多其他的细节,就不在这里分析了。

    方法 描述 singletonObject池
    1.doGetBean("A") 获取bean A singleton:
    earlySingleton:
    singletonFactory:
    2.getSingleton("A") 直接取singleton A,所有池没有A所以找不到 singleton:
    earlySingleton:
    singletonFactory:
    第2步getSingleton("A")结束 singleton:
    earlySingleton:
    singletonFactory:
    3. getSingleton("A", ObjectFactory) 前面已经了解带ObjectFactory参数的getSingleton方法其实包含了创建和注册bean。根据下面源码,调用ObjectFacotry的getObject方法其实就是调用BeanFacotry的子类实现的createBean singleton:
    earlySingleton:
    singletonFactory:
    4.createBean("A",..) getSingleton("A", ObjectFactory)创建bean的操作 singleton:
    earlySingleton:
    singletonFactory:
    5.doCreateBean("A",..) - singleton:
    earlySingleton:
    singletonFactory:
    6.addSingletonFactory("A", ObjectFactory) 把用于创建A的ObjectFacotry注册到singletonFactories singleton:
    earlySingleton:
    singletonFactory:A
    第6步的方法结束 - singleton:
    earlySingleton:
    singletonFactory:A
    7.populateBean("A",..) 给A注入依赖 singleton:
    earlySingleton:
    singletonFactory:A
    8.doGetBean("B") 因为A依赖B,所以需要查找B singleton:
    earlySingleton:
    singletonFactory:A
    9.getSingleton("B") 获取B的单例 singleton:
    earlySingleton:
    singletonFactory:A
    第9步执行的方法结束 - singleton:
    earlySingleton:
    singletonFactory:A
    10. getSingleton("B", ObjectFactory) 因为B还没创建所以创建B singleton:
    earlySingleton:
    singletonFactory:A
    11.createBean("B",..) 创建B singleton:
    earlySingleton:
    singletonFactory:A
    12.doCreateBean("B",..) - singleton:
    earlySingleton:
    singletonFactory:A
    13.addBeanFactory("B",facotry) 把用于创建B的ObjectFacotry注册到singletonFactories singleton:
    earlySingleton:
    singletonFactory:A,B
    14.populateBean("B",..) 注入B的依赖 singleton:
    earlySingleton:
    singletonFactory:A,B
    15.doGetBean("A") 因为B依赖了A,所以查找A singleton:
    earlySingleton:
    singletonFactory:A,B
    16.getSingleton("A") 这个时候已经有A的ObjectFacotry了,根据前面的代码,getSingleton会用objectFactory创建出Bean A,然后把A的objectFactory移除,再把Bean A放到earlySingletonObjects singleton:
    earlySingleton:A
    singletonFactory:B
    第15,16步结束 成功创建Bean A singleton:
    earlySingleton:A
    singletonFactory:B
    第14步结束 成功注入Bean A singleton:
    earlySingleton:A
    singletonFactory:B
    第11,12,13步结束 成功创建Bean B singleton:
    earlySingleton:A
    singletonFactory:B
    17.addSingleton("B", Bean B); 把创建成功的Bean B注册到singletonObjects singleton:B
    earlySingleton:A
    singletonFactory:
    第10步结束 singleton:B
    earlySingleton:A
    singletonFactory:
    第7,8,9结束 成功把beanB 注入到Bean A singleton:B
    earlySingleton:A
    singletonFactory:
    18.addSingleton("A", Bean B); 添加A到singletonObjects singleton:A,B
    earlySingleton:
    singletonFactory:
    第1,3结束 成功创建A singleton:A,B
    earlySingleton:
    singletonFactory:
    部分源码:

    3.getSingleton("A", ObjectFactory)

    sharedInstance = getSingleton(beanName, () -> {
        try {
            return createBean(beanName, mbd, args);
        }
        catch (BeansException ex) {
            destroySingleton(beanName);
            throw ex;
        }
    });
    

    6.addSingletonFactory(beanName, ObjectFactory)

    // bean这个参数就是new出来未注入的bean
    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    
    inCreationCheckExclusions

    getSingleton(String beanName, ObjectFactory<?> singletonFactory)这个方法创建之前bean之前会把beanName添加到singletonsCurrentlyInCreation,但在添加之前还要检查是否在inCreationCheckExclusions这个set里面,在这个set里面的beanName是不检查创建的名单,也就是如果要创建的bean是在inCreationCheckExclusions里面就不会添加到singletonsCurrentlyInCreation。

    public void setCurrentlyInCreation(String beanName, boolean inCreation) {
        Assert.notNull(beanName, "Bean name must not be null");
        if (!inCreation) {
            this.inCreationCheckExclusions.add(beanName);
        }
        else {
            this.inCreationCheckExclusions.remove(beanName);
        }
    }
    

    通过这个方法可以设置某个bean不注册进earlySingletonObjects,假如互相依赖的两个bean都不注册进earlySingletonObjects,那就会抛出异常。

    DefaultSingletonBeanRegistry的成员变量

    我们知道DefaultSingletonBeanRegistry主要维护管理了BeanFactory的单例Bean,除了singletonObjects这个管理了所有单例的map外,还有很多其他成员变量。我们来看一下DefaultSingletonBeanRegistry的所有成员变量。

    /** Cache of singleton objects: bean name to bean instance. */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
    
    /** Cache of singleton factories: bean name to ObjectFactory. */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
    
    /** Cache of early singleton objects: bean name to bean instance. */
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
    

    singletonObjects,singletonFactories,earlySingletonObjects对于这三个变量,上面已经有了很大的篇幅介绍,单例的注册也主要是维护这几个map。

    /** Names of beans that are currently in creation. */
    private final Set<String> singletonsCurrentlyInCreation =
            Collections.newSetFromMap(new ConcurrentHashMap<>(16));
    
    /** Names of beans currently excluded from in creation checks. */
    private final Set<String> inCreationCheckExclusions =
            Collections.newSetFromMap(new ConcurrentHashMap<>(16));
    

    这两个set前面也有介绍到,主要是用来判断某个是否正在被创建,是bean是否循环的主要依据。

    /** List of suppressed Exceptions, available for associating related causes. */
    @Nullable
    private Set<Exception> suppressedExceptions;
    

    用来纪录所有创建bean时相关的异常。

    /** Disposable bean instances: bean name to disposable instance. */
    private final Map<String, Object> disposableBeans = new LinkedHashMap<>();
    
    /** Map between containing bean names: bean name to Set of bean names that the bean contains. */
    private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<>(16);
    
    /** Map between dependent bean names: bean name to Set of dependent bean names. */
    private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);
    
    /** Map between depending bean names: bean name to Set of bean names for the bean's dependencies. */
    private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);
    

    待续...

    相关文章

      网友评论

        本文标题:Spring - BeanFactory 之 Singleton

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