spring的bean作用域有几种,开发中需要注意啥?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring的bean作用域有几种,开发中需要注意啥?相关的知识,希望对你有一定的参考价值。

Spring中Bean的五个作用域

当通过spring容器创建一个Bean实例时,不仅可以完成Bean实例的实例化,还可以为Bean指定特定的作用域。Spring支持如下5种作用域:

    singleton:单例模式,在整个Spring IoC容器中,使用singleton定义的Bean将只有一个实例

    prototype:原型模式,每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例

    request:对于每次HTTP请求,使用request定义的Bean都将产生一个新实例,即每次HTTP请求将会产生不同的Bean实例。只有在Web应用中使用Spring时,该作用域才有效

    session:对于每次HTTP Session,使用session定义的Bean豆浆产生一个新实例。同样只有在Web应用中使用Spring时,该作用域才有效

    globalsession:每个全局的HTTP Session,使用session定义的Bean都将产生一个新实例。典型情况下,仅在使用portlet context的时候有效。同样只有在Web应用中使用Spring时,该作用域才有效

    其中比较常用的是singleton和prototype两种作用域。对于singleton作用域的Bean,每次请求该Bean都将获得相同的实例。容器负责跟踪Bean实例的状态,负责维护Bean实例的生命周期行为;如果一个Bean被设置成prototype作用域,程序每次请求该id的Bean,Spring都会新建一个Bean实例,然后返回给程序。在这种情况下,Spring容器仅仅使用new 关键字创建Bean实例,一旦创建成功,容器不在跟踪实例,也不会维护Bean实例的状态。

    如果不指定Bean的作用域,Spring默认使用singleton作用域。Java在创建Java实例时,需要进行内存申请;销毁实例时,需要完成垃圾回收,这些工作都会导致系统开销的增加。因此,prototype作用域Bean的创建、销毁代价比较大。而singleton作用域的Bean实例一旦创建成功,可以重复使用。因此,除非必要,否则尽量避免将Bean被设置成prototype作用域。

    曾经面试的时候有面试官问我spring的controller是单例还是多例,结果
    我傻逼的回答当然是多例,要不然controller类中的非静态变量如何保证是线程安全的,这样想起似乎是对的,但是不知道(主要是我没看过
    spring的源码,不知道真正的内在意图)为什么spring的controller是单例的。

    先看看spring的bean作用域有几种,分别有啥不同。

    spring bean作用域有以下5个:

    singleton:单例模式,当spring创建applicationContext容器的时候,spring会欲初始化所有的该作用域实例,加上lazy-init就可以避免预处理;

    prototype:原型模式,每次通过getBean获取该bean就会新产生一个实例,创建后spring将不再对其管理;

    ====下面是在web项目下才用到的===

    request:搞web的大家都应该明白request的域了吧,就是每次请求都新产生一个实例,和prototype不同就是创建后,接下来的管理,spring依然在监听

    session:每次会话,同上

    global session:全局的web域,类似于servlet中的application

    好了,上面都说了spring的controller默认是单例,那很自然就是singleton了。

    再看一个例子,看看单例会不会有我说的那种问题(就是类中定义的非静态变量线程安全问题),当然下面这个例子我是实验过的, 要不然也不敢发出来

    为什么spring要默认是单例呢?原因有二:

    1、为了性能。

    2、不需要多例。

    1、这个不用废话了,单例不用每次都new,当然快了。

    2、不需要实例会让很多人迷惑,因为spring mvc官方也没明确说不可以多例。

     我这里说不需要的原因是看开发者怎么用了,如果你给controller中定义很多的属性,那么单例肯定会出现竞争访问了。

     因此,只要controller中不定义属性,那么单例完全是安全的。下面给个例子说明下:


    默认单例的

    1|2

    package
    com.lavasoft.demo.web.controller.lsh.ch5;

    import
    org.springframework.context.annotation.Scope;

    import
    org.springframework.stereotype.Controller;

    import
    org.springframework.ui.ModelMap;

    import
    org.springframework.web.bind.annotation.RequestMapping;

    /**

    * Created by Administrator on 14-4-9.

    *

    * @author leizhimin 14-4-9 上午10:55

    */

    @Controller

    @RequestMapping("/demo/lsh/ch5")

    public
    class MultViewController

    privateintindex =
    0;         //非静态

       @RequestMapping("/show")

       publicStringtoShow(ModelMap model)

           System.out.println(++i);

           return"/lsh/ch5/show";

       

       @RequestMapping("/test")

       publicStringtest()

           System.out.println(++i);

           return"/lsh/ch5/test";

       



    改为多例的(就是在class上面加一个@Scope("request")):

    1 | 1

    从此可见,单例是不安全的,会导致属性重复使用。

    最佳实践:

    1、不要在controller中定义成员变量。

    2、万一必须要定义一个非静态成员变量时候,则通过注解@Scope("prototype"),将其设置为多例模式。
参考技术A 作用域随便搜搜也就知道了,基本都是用单例,特殊情况可以用每次请求一个实例,还有一个会话一个实例等等搜搜了解下怎么回事

需要注意什么,说白了就是要搞清楚单例和非单例的区别,以及什么情况下可以默认单例
单例很明显节省内存,而且由spring管理,服务启动时就预加载了,运行时就没有了创建和销毁的消耗,所以肯定是尽量用单例
既然用单例就一定要考虑并发情况下安全问题(多线程操纵一个实例会不会有问题,怎么才能没问题)。显然的,并发安全问题在于资源竞争,只要单例的类没有成员变量,对它自己来说就是安全的(通过它去竞争别的资源跟它没关系)

说个最简单的例子,controller,service这些,基本都只是操作,不会带成员变量这种有状态的东西,所以就默认单例。但是他们操作的domain,每一个实体都是不一样的,肯定不会把它弄个单例交给spring

spring bean的作用域之间有啥区别

常用的spring bean的作用于scope,单例、原型、session、request
单例和原型区别就是,单例在整个springapplicationcontext里面只有这一个,其他任何bean在调用这个bean的时候都是这一个;原型就是每次调用或者说装配的时候,都会新生成一个bean。
session和request的区别,每个session里面用的都是一个bean,每个request里面都是用一个bean
参考技术A spring容器中的bean可以分为5个范围。
1. singleton:这种bean范围是默认的,这种范围确保不管接受到多少个请求,每个容器中只有一个bean的实例,单例的模式由bean factory自身来维护。
2. prototype:原形范围与单例范围相反,为每一个bean请求提供一个实例。
3. request:在请求bean范围内会每一个来自客户端的网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。
4. Session:与请求范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效。
5. global-session:global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话,那么这全局变量需要存储在global-session中。

以上是关于spring的bean作用域有几种,开发中需要注意啥?的主要内容,如果未能解决你的问题,请参考以下文章

在Spring中,Bean有几种作用域?

Spring中支持几种作用域?

spring的controller默认是单例还是多例

spring配置文件中能够用到的bean的作用域有哪些

Java开发需要学什么!在java中创建线程有几种方法

spring 组件和 bean 的作用域有啥区别? [复制]