前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring Bean 作用域详解

Spring Bean 作用域详解

作者头像
happyJared
发布2019-09-30 17:02:52
1K0
发布2019-09-30 17:02:52
举报
文章被收录于专栏:happyJaredhappyJared

在 Spring 中,那些组成应用程序的主体,以及由 Spring IOC 容器所管理的对象,被称之为 bean。简单地讲,bean 就是由 IOC 容器初始化、装配及管理的对象,除此之外,bean 就与应用程序中的其他对象没有什么区别了,而 bean 的定义以及 bean 相互间的依赖关系,将通过配置元数据来描述。

Spring 中的 bean 默认都是单例的,在多线程程序下,这些单例 Bean 是如何保证线程安全的呢?

例如对于 Web 应用来说,Web 容器对于每个用户的请求,都会创建一个单独的 Sevlet 线程来处理请求,引入 Spring 框架后,每个 Action 都是单例的,那么对于 Spring 托管的单例 Service Bean,如何保证其安全呢?

答案是:Spring 的单例是基于 BeanFactory,也就是 Spring 容器的,单例 Bean 在此容器内只有一个,Java 的单例是基于 JVM,每个 JVM 内只有一个实例。

在大多数情况下。单例 bean 是很理想的方案。不过,有时候系统所使用的类是易变的,它们会保持一些状态,因此重用是不安全的。在这种情况下,将 class 声明为单例就显得不是那么明智了。因为对象会被污染,重用的时候可能会出现意想不到的问题,所以 Spring 定义了支持多种作用域的 bean。

bean 的作用域

创建一个 bean 定义,其实质是用该 bean 定义对应的类来创建真正实例的 “配方”。把 bean 定义看成是配方很有意义,它与 class 很类似,只根据一张 “处方” 就可以创建多个实例,不仅可以控制注入到对象中的各种依赖和配置值,还可以控制该对象的作用域。这样可以灵活选择所建对象的作用域,而不必在 Java Class 级定义作用域。如下表所示,Spring Framework 支持五种作用域。

Spring 五种作用域

以上五种作用域中,request、sessionglobal session 三种作用域,仅能用在基于 web 的 Spring ApplicationContext 环境。

singleton:唯一 bean 实例

当一个 bean 的作用域为 singleton 时,那 Spring IoC 容器中只会存在一个共享的 bean 实例,并且所有对 bean 的请求,只要 id 与该 bean 定义相匹配,则只会返回 bean 的同一实例。 singleton 是单例类型 (对应于单例模式),就是在创建容器时就同时创建一个该 bean 的对象,不管是否使用,不过可以指定 Bean 节点的 lazy-init="true" 来延迟初始化 bean,这时候,只有在第一次获取 bean 时才会初始化 bean,以后每次获取到的对象都是同一个对象。注意,singleton 作用域是 Spring 中的缺省作用域。如果要显示在 XML 中将 bean 定义成 singleton ,可以这样配置:

代码语言:javascript
复制
<bean id="ServiceImpl" class="cn.mariojd.service.ServiceImpl" scope="singleton">

也可以通过 @Scope 注解(还可以显示指定 bean 的作用范围)的方式:

代码语言:javascript
复制
@Service
@Scope("singleton")
public class ServiceImpl {

}

prototype:每次请求都会创建一个新的 bean 实例

当一个 bean 的作用域为 prototype,表示一个 bean 的定义对应多个对象实例。prototype 作用域的 bean 会导致每次在对该 bean 请求(将其注入到另一个 bean 中,或者以程序的方式调用容器的 getBean() 方法)时,都会创建一个新的 bean 实例。prototype 是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取 bean 的时候才去创建一个对象,而且每次获取到的对象都不是同一个对象。

总之,对有状态的 bean 应该使用 prototype 作用域,而对无状态的 bean 则应该使用 singleton 作用域。在 XML 中将 bean 定义成 prototype ,可以这样配置:

代码语言:javascript
复制
<bean id="account" class="cn.mariojd.DefaultAccount" scope="prototype"/>  
# 或者
<bean id="account" class="cn.mariojd.DefaultAccount" singleton="false"/> 

request:每次 HTTP 请求都会产生新的 bean,该 bean 仅在当前 HTTP request 内有效

request 作用域只适用于 Web 程序,每一次 HTTP 请求都会产生一个新的 bean,同时该 bean 仅在当前 HTTP request 内有效,当请求结束后,该对象的生命周期即结束。在 XML 中将 bean 定义成 request ,可以这样配置:

代码语言:javascript
复制
<bean id="loginAction" class=cn.mariojd.LoginAction" scope="request"/>

session:每次 HTTP 请求都会产生新的 bean,该 bean 仅在当前 HTTP session 内有效

session 只适用于 Web 程序,session 作用域表示该针对每一次 HTTP 请求都会产生一个新的 bean,同时该 bean 仅在当前 HTTP session 内有效。当HTTP session 最终被废弃的时候,在该 HTTP session 作用域内的 bean 也会被销毁掉。

代码语言:javascript
复制
<bean id="userPreferences" class="cn.mariojd.UserPreferences" scope="session"/>

globalSession:伴随应用本身的全局作用域

global session 作用域类似于标准的 HTTP session 作用域,不过仅仅在基于 portlet 的 web 应用中才有意义。Portlet 规范定义了全局 Session 的概念,它被所有构成某个 portlet web 应用的各种不同的 portlet 所共享。在 global session 作用域中定义的 bean ,将被限定于全局 portlet Session 的生命周期范围内。

代码语言:javascript
复制
<bean id="user" class="cn.mariojd.Preferences "scope="globalSession"/>
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.09.30 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • bean 的作用域
    • singleton:唯一 bean 实例
      • prototype:每次请求都会创建一个新的 bean 实例
        • request:每次 HTTP 请求都会产生新的 bean,该 bean 仅在当前 HTTP request 内有效
          • session:每次 HTTP 请求都会产生新的 bean,该 bean 仅在当前 HTTP session 内有效
            • globalSession:伴随应用本身的全局作用域
            相关产品与服务
            容器服务
            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档