Spring缓存中获取单例bean

1. 什么问题(what)?

手动获取新增的spring的bean,一直获取不到。程序报:testBean no bean named is defined。

加载程序代码

//加载spring配置文件
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                new String[] { "application.xml" });
        //启动配置文件
        context.start();

        System.out.println(context.getBean("testBean2"));

application.xml 配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://code.alibabatech.com/schema/dubbo
        http://code.alibabatech.com/schema/dubbo/dubbo.xsd
        ">

        <!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
    <dubbo:application name="hehe_consumer" />

    <dubbo:reference id="testBean" version="1.0.0" retries="0"
            group="test" interface=" x.x.x.x.x" 
            url="xxx"
            check="false"  timeout="42000"/>

    <!-- 新增的Bean -->
    <dubbo:reference id="testBean2" version="1.0.0" retries="0"
            group="test" interface="x.x.x.x.x" 
            url="xxx"
            check="false"  timeout="42000"/>

</beans>
2. 解决思路

第一步:context.getBean("testBean2")此行代码的参数Bean名称是否正确(正确无误)
第二步:application.xml 重命名为application2.xml(果然能获取testBean2对象)

3. 为什么会出现此问题

在application.xm配置文件新增testBean2之前 ,
ClassPathXmlApplicationContext`手动加载配置文件只将testBean对象加入在spring容器的缓存中,新增testBean2之后,从spring容器的缓存中是无法获取testBean2的对象。除非将application.xml 重命名为application2.xml,重新启动手动加载。

4. 总结

spring基础知识不扎实

知识点转载地址

5. 缓存中获取单例bean

介绍过FactoryBean的用法后,我们就可以了解bean加载的过程了。前面已经提到过,单例在Spring的同一个容器内只会被创建一次,后续再获取bean直接从单例缓存中获取,当然这里也只是尝试加载,首先尝试从缓存中加载,然后再次尝试尝试从singletonFactories中加载。因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,Spring创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光加入到缓存中,一旦下一个bean创建时需要依赖上个bean,则直接使用ObjectFactory。

public Object getSingleton(String beanName) {  
    //参数true设置标识允许早期依赖    
    return getSingleton(beanName, true);  
}  

protected Object getSingleton(String beanName, boolean allowEarlyReference) {  
        //检查缓存中是否存在实例  
        Object singletonObject = this.singletonObjects.get(beanName);  
        if (singletonObject == null) {  
            //如果为空,则锁定全局变量并进行处理  
            synchronized (this.singletonObjects) {  
                //如果此bean正在加载则不处理  
                singletonObject = this.earlySingletonObjects.get(beanName);  
                if (singletonObject == null && allowEarlyReference) {  
                    //当某些方法需要提前初始化的时候则会调用addSingletonFactory方法将对应的ObjectFactory初始化策略存储在singletonFactories  
                    ObjectFactory singletonFactory = this.singletonFactories.get (beanName);  
                    if (singletonFactory != null) {  
                        //调用预先设定的getObject方法  
                        singletonObject = singletonFactory.getObject();  
                        //记录在缓存中,earlySingletonObjects和singletonFactories互斥  
                        this.earlySingletonObjects.put(beanName, singletonObject);  
                        this.singletonFactories.remove(beanName);  
                    }  
                }  
            }  
        }  
        return (singletonObject != NULL_OBJECT ? singletonObject : null);  
    }  

这个方法因为涉及循环依赖的检测,以及涉及很多变量的记录存取,所以让很多读者摸不着头脑。这个方法首先尝试从singletonObjects里面获取实例,如果获取不到再从earlySingleton Objects里面获取,如果还获取不到,再尝试从singletonFactories里面获取beanName对应的ObjectFactory,然后调用这个ObjectFactory的getObject来创建bean,并放到earlySingleton Objects里面去,并且从singletonFacotories里面remove掉这个ObjectFactory,而对于后续的所有内存操作都只为了循环依赖检测时候使用,也就是在allowEarlyReference为true的情况下才会使用。

这里涉及用于存储bean的不同的map,可能让读者感到崩溃,简单解释如下。

singletonObjects:用于保存BeanName和创建bean实例之间的关系,bean name –> bean instance。

singletonFactories:用于保存BeanName和创建bean的工厂之间的关系,bean name –> ObjectFactory。

earlySingletonObjects:也是保存BeanName和创建bean实例之间的关系,与singletonObjects的不同之处在于,当一个单例bean被放到这里面后,那么当bean还在创建过程中,就可以通过getBean方法获取到了,其目的是用来检测循环引用。

registeredSingletons:用来保存当前所有已注册的bean。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值