Spring的Bean-singleton模式

来源:互联网 发布:北京美工设计培训 编辑:程序博客网 时间:2024/06/05 14:29

一.问题
在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模式比较方便。

阅读全文
0 0
原创粉丝点击