概念
在 spring ioc&di
戒断,我们学习了 spring
是如何帮助我们管理对象的
- 通过
@controller
,@service
,@repository
,@component
,@configuration
,@bean
来声明bean
对象 - 通过
applicationcontext
或者beanfactory
来获取对象 - 通过
@autowired
,setter
方法或者构造方法等来为应用程序注入所依赖的bean
对象
我们来简单回顾一下
- 通过
@bean
声明bean
,把bean
存在spring
容器中
public class dog { private string name; public void setname(string name) { this.name = name; } }
@component public class dogbeanconfig { @bean public dog dog() { dog dog = new dog(); dog.setname("旺旺"); return dog; } }
- 从
spring
容器中获取bean
- 通过在代码中直接注入
applicationcontext
的方式
- 通过在代码中直接注入
@springboottest class applicationtests { @autowired private applicationcontext applicationcontext; @test void contextloads() { dogbeanconfig dog1 = applicationcontext.getbean(dogbeanconfig.class);; system.out.println(dog1); } }
司改代码,从 spring
容器中多次获取 bean
@springboottest class applicationtests { @autowired private applicationcontext applicationcontext; @test void contextloads() { dogbeanconfig dog1 = applicationcontext.getbean(dogbeanconfig.class);; system.out.println(dog1); dogbeanconfig dog2 = applicationcontext.getbean(dogbeanconfig.class);; system.out.println(dog2); } }
观察运行结果
发现输出的 bean
对象地址是一样的,说明每次从 spring
容器中取出来的对象都是同一个
- 这也是“单例模式”
- 单例模式:确保一个类只有一个实例,多次创建也不会创建出多个实例
bean
的作用域是值 bean
在 spring
框架中的某种行为模式
比如单例作用域:表示 bean
在整个 spring
中只有一份,它是全局共享的。那么当其他人修改了这个值之后,那么另一个人读到的就是被修改后的值
修改上述代码,给 usercontroller
添加属性 name
@springboottest class applicationtests { @autowired private applicationcontext applicationcontext; @test void contextloads() { dog dog1 = applicationcontext.getbean(dog.class); dog1.setname("狗狗1"); system.out.println(dog1); system.out.println(dog1.getname()); dog dog2 = applicationcontext.getbean(dog.class);; system.out.println(dog2); system.out.println(dog2.getname()); } }
观察运行结果:
dog1
和dog2
为同一个对象,dog2
拿到了dog1
设置的值
那能不能将 bean
对象设置为非单例的(每次获取的 bean
都是一个新对象呢)
- 这就是
bean
的不同作用域了
bean 的作用域
在 spring
中支持 6 中作用域,后 4 种在 spring mvc
环境才生效
singleton
:单例作用域- 每个
spring ioc
容器内同名称的bean
只有一个实例(单例)(默认)
- 每个
prototype
:原型作用域(多例作用域)- 每次使用该
bean
时会创建新的实例(非单例)
- 每次使用该
request
:请求作用域- 每个
http
请求生命周期内,创建新的实例(web
环境中,了解)
- 每个
session
:会话作用域- 每个
http session
生命周期内,创建新的实例(web
环境中,了解)
- 每个
application
:全局作用域- 每个
servletcontext
生命周期里内,创建新的实例(web
环境中,了解)
- 每个
websocket
:http websocket
作用域- 每个
websocket
生命周期内,创建新的实例(web
环境中,了解)
- 每个
我们来看简单的代码实现
定义几个不同作用域的 bean
@component public class dogbeanconfig { @bean public dog dog() { dog dog = new dog(); dog.setname("旺旺"); return dog; } @bean @scope(configurablebeanfactory.scope_singleton) public dog singledog() { dog dog = new dog(); return dog; } @bean @scope(configurablebeanfactory.scope_prototype) public dog prototype() { dog dog = new dog(); return dog; } @bean @requestscope public dog requestdog() { dog dog = new dog(); return dog; } @bean @sessionscope public dog sessiondog() { dog dog = new dog(); return dog; } @bean @applicationscope public dog applicationdog() { dog dog = new dog(); return dog; } }
@requestscope
等同于@scope (value = webapplicationcontext.scope_request, proxymode = scopedproxymode.target_class)
@sessionscope
等同于@scope (value =webapplicationcontext.scope_session, proxymode =scopedproxymode.target_class)
@applicationscope
等同于@scope (value =webapplicationcontext. scope_application, proxymode =scopedproxymode. target_class)
proxymode
⽤来为 springbean
设置代理 .proxymode = scopedproxymode.target_class
表⽰这个 bean
基于 cglib
实现动态代理,request
,session
和 application
作⽤域的 bean
需要设置 proxymode
代码测试
测试不同作用域的 bean
取到的对象是否一样
@restcontroller public class dogcontroller { @autowired private dog singledog; @autowired private dog prototypedog; @autowired private dog requestdog; @autowired private dog sessiondog; @autowired private dog applicationdog; @autowired private applicationcontext applicationcontext; @requestmapping("/single") public string single(){ dog contexdog = (dog) applicationcontext.getbean("singledog"); return "dog: " + singledog.tostring() + ", contextdog: " + contexdog; } @requestmapping("/prototype") public string prototype() { dog contextdog = (dog) applicationcontext.getbean("prototypedog"); return "dog: " + prototypedog.tostring() + ", contextdog: " + contextdog; } @requestmapping("/request") public string request(){ dog contexdog = (dog) applicationcontext.getbean("requestdog"); return "dog: " + requestdog.tostring() + ", contextdog: " + contexdog; } @requestmapping("/session") public string session() { dog contextdog = (dog) applicationcontext.getbean("sessiondog"); return "dog: " + sessiondog.tostring() + ", contextdog: " + contextdog; } @requestmapping("/application") public string application() { dog contextdog = (dog) applicationcontext.getbean("applicationdog"); return "dog: " + applicationdog.tostring() + ", contextdog: " + contextdog; } }
- 每个请求都获取两次
bean
@autowired
和applicationcontext.getbean("singledog")
都是从spring
容器中获取对象
观察 bean 的作用域
1.单例作用域
地址: http://127.0.0.1:8080/single
多次访问,得到的都是同一个对象,并且 @autowired
和 applicationcontext.getbean()
也是同一个对象
2.多例作用域
地址: http://127.0.0.1:8080/prototype
观察 contextdog
,每次获取的对象都不一样(注入的对象在 spring
容器启动时,就已经注入了,所以多次请求访问也不会发生变化)
3.请求作用域
地址: http://127.0.0.1:8080/request
在一次请求中,@autowired
和 applicationcontext.getbean()
也是同一个对象,但是每次请求,都会重新创建对象
4.会话作用域
地址: http://127.0.0.1:8080/session
在一个 session
中,多次请求,获取到的对象都是同一个
换一个浏览器访问,发现会重新创建对象(另一个 session
)
5.application作用域
地址: http://127.0.0.1:8080/application
在一个应用中,多次访问都是同一个对象
application scope
就是对于整个web
容器来说,bean
的作用域是servletcontext
级别的- 这个和
singleton
有点类似,区别在于:application scope
是servletcontext
的单例,singleton
是一个applicationcontext
的单例 - 在一个
web
容器中applicationcontext
可以有多个(了解即可)
到此这篇关于spring bean的作用域具体实现(单例、多例、请求、会话、application)的文章就介绍到这了,更多相关spring bean作用域内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论