在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 的上下文中有效。

转载于:https://juejin.im/post/5c6a6b08518825787e69e5dd

Spring scope解惑相关推荐

  1. Spring scope 学习笔记

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

  2. spring scope=prototype 学习笔记

    <bean id="meetAction" class="com.web.actions.MeetsAction" scope="prototy ...

  3. 页面每次添加都显示最后一次访问记录spring scope=prototype 学习笔记

    <bean id="meetAction" class="com.web.actions.MeetsAction"  scope="protot ...

  4. Spring scope属性详解

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

  5. Spring @scope注解

    @scope注解使用方式: @scope("prototype") @scope注解可取值: singleton prototype request session global ...

  6. java spring scope_如何在Spring中自定义scope的方法示例

    大家对于 Spring 的 scope 应该都不会默认.所谓 scope,字面理解就是"作用域"."范围",如果一个 bean 的 scope 配置为 sing ...

  7. error:lnk2005 已经在*.obj中定义_如何在 Spring 中自定义 scope

    大家对于 Spring 的 scope 应该都不会默认.所谓 scope,字面理解就是"作用域"."范围",如果一个 bean 的 scope 配置为 sing ...

  8. 如何在 Spring 中自定义 scope

    大家对于 Spring 的 scope 应该都不会默认.所谓 scope,字面理解就是"作用域"."范围",如果一个 bean 的 scope 配置为 sing ...

  9. 系统学习Spring之Spring in action(二)

    每日一叨: 非常抱歉,由于刚刚接触博客园,很多功能都还没有怎么熟悉,所以第一篇文章的排版不够好,一些重要的信息不够醒目,在接下来的文章里,我会有所改善, 若有哪个地方理解的有问题,可以与我交流,我会即 ...

最新文章

  1. SQL GROUP BY 语句
  2. flex--unable to transcode image
  3. 继清华之后,北邮成立人工智能研究院
  4. 点击新建 下拉框选择
  5. You are what you say!
  6. iphone11返回上一级手势怎么设置_苹果iphone12怎么关闭程序appp 怎么返回上一步
  7. 学python好还是不学好_非专业人士有必要学Python吗?
  8. 一些常见http状态码
  9. 44 CO配置-控制-产品成本控制-成本对象控制-实际成本核算/物料分类帐-激活实际成本的在产品
  10. 允许Sublime编辑器在Ubuntu上输入中文
  11. freecplus框架-日期、时间和计时器
  12. 表格无边框,有内框,在table嵌套时,防止出现重复边线
  13. ffmpeg 拼接mp4_ffmpeg 合并 拼接 mp4视频
  14. 软件构造 第三章第三节 抽象数据型(ADT)
  15. 【OpenCV学习笔记】【编程实例】六 (霍夫圆检测续)
  16. 项目经理如何管理团队
  17. FlyMcu - 用于STM32芯片ISP串口程序一键下载的免费软件
  18. java中double类型占几个字节_Java中基本数据类型占几个字节多少位
  19. MySql可视化工具MySQL Workbench使用笔记
  20. MacBook 快捷键

热门文章

  1. ADO.NET 快速入门(四):从数据库填充 DataSet
  2. Linux 高可用(HA)集群之keepalived详解
  3. 常用16 个 Linux 服务器监控命令
  4. Hibernate和Mysql5.1以上版本创建表出错 type=InnDB
  5. ThinkPHP 数据库表结构处理类(简单实用)
  6. ffmpeg文件拼接
  7. 标签之美三——超链接的嵌入
  8. php-nginx超时时间过短导致的post失败
  9. cactiez----监控windows主机 server 2008 r2
  10. Postfix邮件设定相关