Bean 的作用域种类
在 Spring 中⽀持 6 种作⽤域,后 4 种在 Spring MVC 环境才⽣效
1. singleton:单例作⽤域
2. prototype:原型作⽤域(多例作⽤域)
3. request:请求作⽤域
4. session:会话作⽤域
5. application:全局作⽤域
6. websocket:HTTP WebSocket 作⽤域
作用域及其含义
参考文档:https://docs.spring.io/spring-framework/reference/core/beans/factory-scopes.html
代码实现
// Bean 作用域的配置
@Configuration
public class BeanConfig {
// Bean 的默认作用域,单例模式
@Bean
public User user(){
return new User();
}
//作用域: singleton 单例模式
//每个 Spring IoC 容器内同名称的 bean 只有⼀个实例(单例)(默认)
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public User singletonUser(){
return new User();
}
//作用域:prototype 原型(非单例)
//每次获取 bean 时会创建新的实例(⾮单例)
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public User prototypeUser(){
return new User();
}
//作用域:request 请求
//每个 HTTP 请求⽣命周期内,创建新的实例(web环境中)
@Bean
@RequestScope
public User requestUser(){
return new User();
}
//作用域:session 会话
//每个 HTTP Session ⽣命周期内,创建新的实例(web环境中)
@Bean
@SessionScope
public User sessionUser(){
return new User();
}
//作用域:application 应用
@Bean
@ApplicationScope
public User applicationUser(){
return new User();
}
}
@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⽤来为 spring bean 设置代理. proxyMode = ScopedProxyMode.TARGET_CLASS 表⽰这个 Bean 基于 CGLIB 实现动态代理.Request,session和 application 作⽤域的 Bean 需要设置 proxyMode
测试不同作用域的 Bean 取到的对象是否⼀样
@RestController
@RequestMapping("/Bean")
public class BeanController {
//默认作用域下获取的对象
@Qualifier("user") //设置注入对象的名称
@Autowired
private User defaultBean;
//作用域为单例(singleton)时获取的对象
@Qualifier("singletonUser")
@Autowired
private User singletonBean;
//作用域为原型(prototype)时获取的对象
@Qualifier("prototypeUser") //设置注入对象的名称
@Autowired
private User prototypeBean;
//作用域为 HTTP 请求(request)时获取的对象
@Qualifier("requestUser") //设置注入对象的名称
@Autowired
private User requestBean;
//作用域为会话(session)时获取的对象
@Qualifier("sessionUser") //设置注入对象的名称
@Autowired
private User sessionBean;
//作用域为 ServletContext⽣命周期内(application)时获取的对象
@Qualifier("applicationUser") //设置注入对象的名称
@Autowired
private User applicationBean;
//注入 Spring 的 IoC 容器,注意 applicationContext 导入的包是 springframework 的
@Autowired
private ApplicationContext applicationContext;
//默认作用域下获取的对象
@RequestMapping("/default")
public String defaultBean(){
User contextBean=(User) applicationContext.getBean("user");
return "默认作用域下,注入的对象为:"+defaultBean+"在 context 容器中获取的对象为:"+contextBean;
}
//作用域为单例(singleton)时获取的对象
@RequestMapping("/singleton")
public String singletonBean(){
User contextBean=(User) applicationContext.getBean("singletonUser");
return "单例(singleton)作用域下,注入的对象为:"+singletonBean+"在 context 容器中获取的对象为:"+contextBean;
}
//作用域为原型(prototype)时获取的对象
@RequestMapping("/prototype")
public String prototypeBean(){
User contextBean=(User) applicationContext.getBean("prototypeUser");
return "原型(prototype)作用域下,注入的对象为:"+prototypeBean+"在 context 容器中获取的对象为:"+contextBean;
}
//作用域为 HTTP 请求(request)时获取的对象
@RequestMapping("/request")
public String requestBean(){
User contextBean=(User) applicationContext.getBean("requestUser");
return "request 请求作用域下,注入的对象为:"+requestBean+"在 context 容器中获取的对象为:"+contextBean;
}
//作用域为会话(Session)时获取的对象
@RequestMapping("/session")
public String sessionBean(){
User contextBean=(User) applicationContext.getBean("sessionUser");
return "session 会话作用域下,注入的对象为:"+sessionBean+"在 context 容器中获取的对象为:"+contextBean;
}
//作用域为应用(application)时获取的对象
@RequestMapping("/application")
public String applicationBean(){
User contextBean=(User) applicationContext.getBean("applicationUser");
return "application 应用作用域下,注入的对象为:"+applicationBean+"在 context 容器中获取的对象为:"+contextBean;
}
}
观察 Bean 的作用域
单例作用域(singleton)
默认就是单例作用域,所以默认情况下和单例( singleton)作用域下,多次访问,得到的都是同⼀个对象,并且 @Autowired 和 applicationContext.getBean() 也是同⼀个对象.
原型作用域(prototype)
每次获取的对象都不⼀样(注⼊的对象在 Spring 容器启动时,就已经注⼊了,所以多次请求也不会发⽣变化)
请求作⽤域(request)
在⼀次请求中,@Autowired 和 applicationContext.getBean() 也是同⼀个对象. 但是每次请求,都会重新创建对象
会话作⽤域(session)
在⼀个 session 中,多次请求,获取到的对象都是同⼀个.
换⼀个浏览器访问,发现会重新创建对象.(另⼀个 Session )
应用作⽤域(application)
在⼀个应⽤中,多次访问都是同⼀个对象
Application 和 singleton 的区别
Application scope就是对于整个 web 容器来说,bean 的作⽤域是 ServletContext 级别的.这个和 singleton有点类似,区别在于: Application scope是 ServletContext 的单例, singleton 是⼀个 ApplicationContext 的单例.在⼀个 web 容器中 ApplicationContext 可以有多个.(了解即可)