Spring源码之IoC,单例Bean添加到一、二、三级缓存的时机,源码解读

三个缓存都存在于DefaultSingletonBeanRegistry中。以AbstractBeanFactory中的getBean作为入口。

添加到一级缓存的时机

一级缓存主要用于存储单例模式下创建完毕的Bean实例,包括该Bean的实例化,依赖注入,初始化等都完成的一个完整的Bean。

所以添加到一级缓存中的时机:自然是完成Bean的实例化,依赖注入,初始化等操作,生成完整的单例Bean后进行添加的。

源码位置:getBean方法——doGetBean方法——getSingleton创建单例Bean——addSingleton方法

doGetBean方法中创建单例Bean的代码

可以看到,getSingleton方法的入参传入是ObjectFactory类型,使用匿名内部类的方式,传入一个实现了ObjectFactory类的getObject方法的对象,getObject方法通过调用createBean方法完成对象的创建。

                if (mbd.isSingleton()) {
                    sharedInstance = this.getSingleton(beanName, () -> {
                        try {
                            return this.createBean(beanName, mbd, args);
                        } catch (BeansException var5) {
                            this.destroySingleton(beanName);
                            throw var5;
                        }
                    });
                    beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }

getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法源码

1、该方法使用synchronized对一级缓存进行加锁。
2、获取到锁后从一级缓存中取Bean对象,取到则直接返回
3、缓存中取不到,则调用ObjectFactory的getObject方法创建对象
4、最后调用addSingleton方法,把单例Bean添加到缓存中

    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(beanName, "Bean name must not be null");
        synchronized(this.singletonObjects) {
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
                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 (this.logger.isDebugEnabled()) {
                    this.logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
                }

                this.beforeSingletonCreation(beanName);
                boolean newSingleton = false;
                boolean recordSuppressedExceptions = this.suppressedExceptions == null;
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = new LinkedHashSet();
                }

                try {
                    singletonObject = singletonFactory.getObject();
                    newSingleton = true;
                } catch (IllegalStateException var16) {
                    singletonObject = this.singletonObjects.get(beanName);
                    if (singletonObject == null) {
                        throw var16;
                    }
                } catch (BeanCreationException var17) {
                    BeanCreationException ex = var17;
                    if (recordSuppressedExceptions) {
                        Iterator var8 = this.suppressedExceptions.iterator();

                        while(var8.hasNext()) {
                            Exception suppressedException = (Exception)var8.next();
                            ex.addRelatedCause(suppressedException);
                        }
                    }

                    throw ex;
                } finally {
                    if (recordSuppressedExceptions) {
                        this.suppressedExceptions = null;
                    }

                    this.afterSingletonCreation(beanName);
                }

                if (newSingleton) {
                    this.addSingleton(beanName, singletonObject);
                }
            }

            return singletonObject;
        }
    }

addSingleton方法源码

1、该方法使用synchronized对一级缓存进行加锁。获取singletonObjects锁
2、调用put方法添加到一级缓存
3、清理三级缓存singletonFactories中的该Bean
4、清理二级缓存earlySingletonObjects中的该Bean
5、把该Bean添加到成功列表中,registeredSingletons记录已经创建成功的单例名称。

    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);
        }
    }

添加到二级缓存的时机

源码位置:getBean方法——doGetBean方法——getSingleton方法

doGetBean中首次调用getSingleton

getSingleton(beanName)此方法先从一级和二级缓存中取,如果都取不到,允许从三级缓存中取,如果从三级缓存中取到Bean。

如果从三级缓存中取到对应的Bean,则把Bean添加到二级缓存,并在三级缓存中清除

    protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
        String beanName = this.transformedBeanName(name);
        Object sharedInstance = this.getSingleton(beanName);
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                synchronized(this.singletonObjects) {
                    singletonObject = this.singletonObjects.get(beanName);
                    if (singletonObject == null) {
                        singletonObject = this.earlySingletonObjects.get(beanName);
                        if (singletonObject == null) {
                            ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                            if (singletonFactory != null) {
                                singletonObject = singletonFactory.getObject();
                                // 添加到二级缓存
                                this.earlySingletonObjects.put(beanName, singletonObject);
                                // 在三级缓存中清除
                                this.singletonFactories.remove(beanName);
                            }
                        }
                    }
                }
            }
        }

        return singletonObject;
    }

添加到三级缓存的时机

调用createBeanInstance进行Bean实例化之后,调用populateBean进行依赖注入之前

源码位置:getBean方法——doGetBean方法——addSingletonFactory方法

doGetBean方法调用addSingletonFactory方法的源码

        boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
        if (earlySingletonExposure) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
            }

            this.addSingletonFactory(beanName, () -> {
                return this.getEarlyBeanReference(beanName, mbd, bean);
            });
        }

addSingletonFactory方法源码

1、获取锁
2、添加到三级缓存
3、从二级缓存中进行清理
4、把该Bean添加到成功列表中,registeredSingletons记录已经创建成功的单例名称。

    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);
            }

        }
    }

总结

添加到一级缓存:完成Bean的实例化,依赖注入,初始化等操作,生成完整的单例Bean后进行添加。

添加到二级缓存:通过getBean获取实例,在三级缓存中获取到时,添加到二级缓存,并清理三级缓存。

添加到三级缓存:通过createBeanInstance实例化Bean之后,调用populateBean进行依赖注入之前。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值