Spring的Bean-singleton模式

本文探讨了Spring中Bean的singleton模式,指出它不同于设计模式中的单例,并通过源码分析说明Spring如何管理单例Bean。同时,文章强调了Spring单例Bean的线程安全问题,建议对于有状态的Bean使用prototype模式或采取其他措施确保线程安全。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.问题
在spring中,Bean的scope默认为singleton。可能我们会把spring的singleton与设计模式中的singleon
类比然后等价。事实是:在spring中的singleton不是以单例模式创建,而是在容器中以单例存在。

二.源码分析(这里以spring3.2.0为例)
创建一个示例,通过调试找到入口在:org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean中,这里只贴出主要部分。

如果实例已经存在,则直接取出使用

    //获取已经注册的实例
    Object sharedInstance = getSingleton(beanName);
    //实例已经存在
    if (sharedInstance != null && args == null) {
        if (logger.isDebugEnabled()) {
            if (isSingletonCurrentlyInCreation(beanName)) {
                logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                        "' that is not fully initialized yet - a consequence of a circular reference");
            }
            else {
                logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }
        //如果缓存中已经存在,直接取出
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }

如果实例还不存在,则进行创建

    //如果正在创建,异常返回
    // Fail if we're already creating this bean instance:
    // We're assumably within a circular reference.
    if (isPrototypeCurrentlyInCreation(beanName)) {
        throw new BeanCurrentlyInCreationException(beanName);
    }
    //scope==singleton的创建
    if (mbd.isSingleton()) {
        sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
        public Object getObject() throws BeansException {
            try {
                //createBean()反射创建实例
                return createBean(beanName, mbd, args);
            }
            catch (BeansException ex) {
                // Explicitly remove instance from singleton cache: It might have been put there
                // eagerly by the creation process, to allow for circular reference resolution.
                // Also remove any beans that received a temporary reference to the bean.
                //创建异常则销毁
                destroySingleton(beanName);
                throw ex;
            }
        }
    });
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

    //scope==prototype的创建方式
    else if (mbd.isPrototype()) {
        //创建新实例
        // It's a prototype -> create a new instance.
        Object prototypeInstance = null;
        try {
            //创建前的回调:说明实例已经在创建
            beforePrototypeCreation(beanName);
            //反射创建实例
            prototypeInstance = createBean(beanName, mbd, args);
        }
        finally {
            //创建后的回调:标记实例不存在,因为是多例创建
            afterPrototypeCreation(beanName);
        }
        bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
    }

    //后面还有其他scope的创建
    ......

spring中的单例是只在容器中的存在方式,而不是创建方式。

三.singleton线程安全问题
spring框架中的单例Bean不是线程安全的
spring框架将单例的Bean进行统一管理,但是允许多线程访问。所以对于无状态的Bean(没有实例变量的对象,比如:dao层的Bean),使用singleton是线程安全的;但是对于有状态的Bean(就是有实例变量的对象,比如:模型层的对象),使用singleton就是线程不安全的,解决方法可以是(a):时间换空间:线程同步机制;(b)空间换时间:改用prototype模式;或者使用ThreadLocal。
对于有状态的Bean使用prototype模式比较方便。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值