美文网首页
Spring的单例bean与原型bean

Spring的单例bean与原型bean

作者: 白花蛇草可乐 | 来源:发表于2019-08-21 21:23 被阅读0次

    一、Spring中Bean的scope

    Spring官方文档中给出的bean的scope有五种:Spring官方文档

    • singleton
    • prototype
    • request
    • session
    • global session

    实际上,Spring最基本的scope只有两种,即singleton和prototype。

    可以参看spring源码中的BeanDefinition.java的定义,只有这两种:

        String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
        String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
    

    其他的各种scope都是自行扩展出来的。包括官网文档中没有列出来的 servletContenxt 、thread;SpringCloud提供的refresh等。

    其继承关系大致如下

    各种scope

    二、singletonScope与prototypeScope

    singletonScope,即单例Bean,顾名思义具有单例模式的所有特性,在spring容器里面只会初始化出一个bean实例,存于缓存中。后续的请求都公用这个对象。

    最简单的创建单例bean的方式,就是直接在类名上面加@Service注解。

    prototypeScope,即原型Bean,每次请求时都会创建新的bean实例直接使用。

    创建原型Bean,需要显示指定scope属性。

    <bean id="accountService" class="com.foo.DefaultAccountService" scope="prototype"/>
    

    三、源码

    可以参看spring的 AbstractBeanFactory.java 中的 doGetBean 方法,理解两种bean的使用过程。

    • 对于单例bean
                    // Create bean instance.
                    if (mbd.isSingleton()) {
                        sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                            @Override
                            public Object getObject() throws BeansException {
                                try {
                                    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);
                    }
    
    

    单例bean被存放在这样一个Map中:

        /** Cache of singleton objects: bean name --> bean instance */
        private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
    
    

    上面代码中的 getSingleton 方法,作用就是先根据beanName从map(singletonObjects)中取bean,

    取不到的话,调用后面的singletonFactory的createBean方法创建单例bean(这里的createBean是抽象方法,具体实现交给了各种scope的实现类负责),

    创建成功以后,存入singletonObjects,并将引用返回。

    • 对于原型bean
                    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);
                    }
    

    中规中矩,上来就直接创建,然后分befoew、createBean、after三个生命周期,对于具体实现提供充分的支持。

    至于最后一句 getObjectForBeanInstance,如果上面创建的是一个普通bean则直接返回;如果创建的是一个BeanFactory的实例,则利用工厂实例创建新的bean,然后返回。

    • 对于其他扩展出来的scope

    会利用 接口 Scope.java 中定义的这个方法,调用各扩展scope的实现去创建bean:

    // Return the object with the given name from the underlying scope,
    Object get(String name, ObjectFactory<?> objectFactory);
    

    四、单例bean的优势

    spring中创建的bean默认就是单例bean。

    其优势实际上就是单例自身的各种优势:

    1. 减少系统新创建实例消耗的资源
    2. 减少jvm垃圾回收
    3. 可以从缓存中快速获取到bean

    单例bean也存在缺点,主要表现在在并发环境下的线程不安全。

    相关文章

      网友评论

          本文标题:Spring的单例bean与原型bean

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