在2.0之前只有两种singleton和prototype(网上说的,没去验证),后面增加了session、request、global session三种专门用于web应用程序上下文的Bean

  Singleton

  这是spring的bean的默认的作用域-单例。但是此单例又与设计模式中的单例模式不一样,设计模式的单例在设计模式的文章中再介绍。

  singleton不要简单的理解为全局只有一个,真正的意义是在一个上下文(ApplicationContext)中只有一个。如果在一个项目中有多个ApplicationContext,那么获取的Bean对象就不只一个了

  在同一个容器或上下文中,所有对单例bean的请求,只要id与该bean定义相匹配,都会返回同一个实例。简单说就是bean定义为singleton时,ioc容器只会创建该bean的唯一实例,然后存储在单例缓存(singleton cache)中。

  singleton的bean是无状态的,只有一份,所以无论哪个线程获取的都是同一个同样的实例,具有线程无关性。Spring使用ThreadLocal解决线程安全问题,这就要求在使用singleton的bean时不能存在属性的改变,如果存在属性改变,就需要慎重使用,采用同步来处理多线程问题,或者考虑使用prototype作用域。

  基于上面,我们常用的Controller、Service、Repository、Configuration这些bean基本上都是项目启动就已经初始化完毕,每个bean的属性都已经确定,在运行过程中也不会更改,这样就很适合单例模式。这里再说一下实体类(用@Entity注解修饰的)这个可不是一个bean,试想一下,每次使用实体的时候是不是都是DomainA a = new DomainA();,应该没有人这么用@Autowired private DomainA domianA;

  使用scope的方法如下:

  @Scope(singleton)

  @Component

  public class MainService {...}

  Prototype

  相对应singleton,prototype就属于多例模式,每次请求都会创建一个新的实例,相当于new操作。

  对于prototype类型的bean,spring只负责创建初始化,不会对整个生命周期负责,随后的所有操作都交给客户端来处理

  现在问一个问题,如何声明一个prototype的bean并使用呢?(先不要急着往下看,想一下,就以在ScopeTestController里面注入prototype的PrototypeService来说明)

  ~

  ~

  ~

  ~

  思考中...

  ~

  ~

  ~

  ~

  可能很多人(包括我)开始会以为像以下这种写法就可以

  public interface PrototypeService {

  }

  @Service

  @Scope(prototype)

  public class PrototypeServiceImpl implements PrototypeService {

  }

  @RestController

  public class ScopeTestController {

  @Autowired

  PrototypeService prototypeService;

  @GetMapping(/)

  public void testPrototype() {

  System.out.println(prototypeService);

  }

  }

  启动项目,两次次请求,查看控制台输出

  com.ukirin.idle.web.service.impl.PrototypeServiceImpl@74738f89

  com.ukirin.idle.web.service.impl.PrototypeServiceImpl@74738f89

  ?一样?什么情况?

  其实仔细想一下也就明白了错在哪,Controller是一个单例,在启动时就已经把Service注入了,所以不可能改变,当然现在你可以这么改,将Controller同样改为prototype的。那么恭喜你回答正确,但是,这不是我们的目的,我们的目的是要看在单例中如何使用。

  方法1:从ApplicationContext里面获取

  将Controller里面的代码做以下改动

  @RestController

  public class ScopeTestController {

  // @Autowired

  // PrototypeService prototypeService;

  @Autowired

  WebApplicationContext applicationContext;

  @GetMapping(/)

  public void testPrototype() {

  // System.out.println(prototypeService);

  System.out.println(applicationContext.getBean(PrototypeService.class));

  }

  }

  这样每次都从上下文中请求一个实例,容器对每个请求都实例化一个新的Service,没有问题

  方法2:方法1的变种,采用工厂模式来生成Service

  代码就不写了...

  方法3:使用代理

  很简单,在@Scope里面加上代理模式即可

  @Service

  @Scope(value = prototype, proxyMode = ScopedProxyMode.INTERFACES)

  public class PrototypeServiceImpl implements PrototypeService {

  }

  @RestController

  public class ScopeTestController {

  @Autowired

  PrototypeService prototypeService;

  // @Autowired

  // WebApplicationContext applicationContext;

  @GetMapping(/)

  public void testPrototype() {

  System.out.println(prototypeService);

  // System.out.println(applicationContext.getBean(PrototypeService.class));

  }

  }

  这样,就可以每次获取不同的Service了,这个的原理就是,在初始化Controller的时候并不是讲一个Service的实体注入,而是注入一个代理,当真正调用Service的时候,代理会对其进行依赖解析,并调用真正的实体bean

  额外需要注意的一点是,如果注入的不是接口的实现,而是一个类,那么需要将proxyMode = ScopedProxyMode.INTERFACES改为proxyMode = ScopedProxyMode.TARGET_CLASS

  request

  该作用域将 bean 的定义限制为 HTTP 请求。只在 web-aware Spring ApplicationContext 的上下文中有效

  上述的实验结果是每次请求都会输出不一样的结果,在这里可能会与prototype产生困惑,做以下的实验可以解决你的困惑

  public interface PrototypeService {

  }

  @Service

  @Scope(value = request, proxyMode = ScopedProxyMode.INTERFACES)

  public class PrototypeServiceImpl implements PrototypeService {

  }

  public interface MiddleService {

  void test();

  }

  @Service

  public class MiddleServiceImpl implements MiddleService {

  @Autowired

  PrototypeService prototypeService;

  @Override

  public void test() {

  System.out.println(middle : + prototypeService);

  }

  }

  @RestController

  public class ScopeTestController {

  @Autowired

  MiddleService middleService;

  @Autowired

  PrototypeService prototypeService;

  // @Autowired

  // WebApplicationContext applicationContext;

  @GetMapping(/)

  public void testPrototype() {

  System.out.println(controller : + prototypeService);

  // System.out.println(applicationContext.getBean(PrototypeService.class));

  middleService.test();

  }

  }

  输出结果为:

  controller : com.ukirin.idle.web.service.impl.PrototypeServiceImpl@6b90371c

  middle : com.ukirin.idle.web.service.impl.PrototypeServiceImpl@6b90371c

  然后将作用域改为prototype再测试一下

  输出结果为:

  controller : com.ukirin.idle.web.service.impl.PrototypeServiceImpl@49b2c498

  middle : com.ukirin.idle.web.service.impl.PrototypeServiceImpl@ccb8c47

  结果显而易见

  session

  该作用域将 bean 的定义限制为 HTTP 会话。 只在web-aware Spring ApplicationContext的上下文中有效。

  上述的实验结果是一个会话内输出结果是一样的

  global-session

  该作用域将 bean 的定义限制为全局 HTTP 会话。只在 web-aware Spring ApplicationContext 的上下文中有效。

Spring scope解惑的更多相关文章

  1. Spring Scope:Web项目中如何安全使用有状态的Bean对象?

    Web系统是最常见的Java应用系统之一,现在流行的Web项目多使用ssm或ssh框架,使用spring进行bean的管理,这为我们编写web项目带来了很多方便,通常,我们的controler层使用注 ...

  2. Spring scope

    scope用来声明IOC容器中的对象应该处的限定场景或者说该对象的存活空间,即在IOC容器在 对象进入相应的scope之前,生成并装配这些对象,在该对象不再处于这些scope的限定之后,容器通常会销毁 ...

  3. spring scope="prototype", scope="session"

    转自: http://www.cnblogs.com/JemBai/archive/2010/11/10/1873954.html struts+spring action应配置为scope=&quo ...

  4. Spring——scope详解(转载)

    摘自<spring 解密> scope用来声明IOC容器中的对象应该处的限定场景或者说该对象的存活空间,即在IOC容器在 对象进入相应的scope之前,生成并装配这些对象,在该对象不再处于 ...

  5. spring scope 作用域

    转自:http://www.cnblogs.com/qq78292959/p/3716827.html 今天研究了一下scope的作用域.默认是单例模式,即scope="singleton& ...

  6. Spring scope注解

    Spring注解中@scope默认为单例模式(singleton) 设置写法@scope("") 1.singleton单例模式 全局有且仅有一个实例 2.prototype原型模 ...

  7. Spring scope 配置

    Scope 描述的是 Spring 容器如何新建Bean的实例,Spring的Scope有以下几种,通过@Scope来注解实现: 1. Singleton: 一个Spring容器中只有一个Bean的实 ...

  8. spring scope 属性的取值

    Spring 容器是通过单例模式创建 Bean 对象的,也就是说,默认情况下,通过调用 ac.getBean("mybean")方法获得的对象都是同一个 mybean 对象 使用单 ...

  9. spring scope prototype与singleton区别

    1.singleton作用域  当一个bean的作用域设置为singleton, 那么Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配 ...

随机推荐

  1. 关于 Intellij IDEA Ultimate Edition 14.1控制台中文乱码 解决

    经过尝试,我发现,乱码主要是跟控制台右下角的编码有关  如下图 当然IDE Encoding 和 Project Encoding 你可以都设置位UTF-8 或者都设置为GBK    如下图:

  2. 阿里巴巴Java开发规约IDEA插件安装及使用

    技术交流群:233513714   一.通过Jetbrains官方仓库安装 1. 打开 Settings >> Plugins >> Browse repositories.. ...

  3. Checksum 磁盘扇区故障检测

    w https://en.wikipedia.org/wiki/Checksum https://zh.wikipedia.org/wiki/校验和 A checksum is a small-siz ...

  4. 2015-03-10——简析javascript对象

    对于构造函数,它是Function对象的一个实例,可以定义自己的静态成员先实例化出对象,后执行function中内部代码 静态成员:  var abc = function () {};  //既是一 ...

  5. scrapy item

    item item定义了爬取的数据的model item的使用类似于dict 定义 在items.py中,继承scrapy.Item类,字段类型scrapy.Field() 实例化:(假设定义了一个名 ...

  6. Django框架错误处理

    错误处理 在一些网站开发中.经常会需要捕获一些错误,然后将这些错误返回比较优美的界面,或者是将这个错误的请求做一些日志保存.那么我们本节就来讲讲如何实现. 常用的错误码: 404:服务器没有指定的ur ...

  7. MYSQL SET ENUM字段类型

    show create table stu;//显示建表语句 create table t1(t enum('a','b','c')); insert into t1 values('a'); cre ...

  8. django的序列化问题

    Django中的序列化主要应用在将数据库中检索的数据返回给客户端用户,特别的Ajax请求一般返回的为Json格式 1.serializers from django.core import seria ...

  9. python1变量,表达式和语句

    1.变量和类型 变量是指向各种类型值的名字,以后再用到某个值时,直接引用这个名字即可,不用再写具体的值,在python中,变量的使用环境非常宽松,没有明显的变量声明,而且类型不是固定的.如果你不能确定 ...

  10. Nullable类型的问题处理

    public class Calc { public long? Number { get; set; } public long Number1 { get; set; } public long ...