概念
在 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作用域内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论