只有当使用web-aware的Spring ApplicationContext实现(如XmlWebApplicationContext)时,request
、session
和 application
的作用域才可用。如果将这些作用域与常规Spring IoC容器(如ClassPathXmlApplicationContext)一起使用,则会抛出一个举报未知bean作用域的IllegalStateException。
这几个作用域都是基于web,所以在org.springframework.web.context.annotation
包下都进行了继承。
为了在request
,session
和application
级别(web作用域bean)支持bean的作用域,在定义bean之前需要进行初始化Web配置Configuration。
Spring容器通过为每个HTTP请求使用bean定义来创建bean的新实例。也就是说,bean的作用域是在HTTP请求级别。可以随心所欲地更改已创建实例的内部状态,因为从相同的bean定义创建的其他实例看不到这些状态更改。它们是针对个别要求的。当请求完成处理时,将丢弃作用域为该请求的bean。
<bean id="loginController" class="com.example.LoginController" scope="request"/>
@Scope("request")
@Controller
public class LoginController{
private int flag = 0;
@RequestMapping("/login")
public int login(){
return flag++;
}
}
或者使用@RequestScope
@RestController
@RequestScope
public class LoginController {
private int flag = 0;
@RequestMapping("/login")
public int login(){
return flag++;
}
}
启动项目,访问得到的效果与Prototype的一样,每刷新一次页面就会有一个新的请求,创建的是一个新的实例;与Prototype不同的是request不需要开发人员去实现bean后处理器来清除实例,这些生命周期由web容器接管。
Spring容器通过在单个HTTP会话的生命周期中使用bean定义来创建bean的新实例。换句话说,bean有效地限定在HTTP会话级别。与request作用域内bean一样,可以改变已创建实例的内部状态,即使其他HTTP会话实例也使用相同的实例创建这个bean的定义,它也看不到这些变化,因为他们是特定于一个单独的HTTP会话。当HTTP Session最终被丢弃时,限定在该特定HTTP Session范围内的bean也将被丢弃。
在一个session生命周期内共享操作用户的资源信息。
<bean id="userController" class="com.example.UserController" scope="session"/>
@RestController
@Scope("session")
public class UserController {
private int flag = 0;
@RequestMapping("/getUser")
public int getUser(){
return flag++;
}
}
或者
@RestController
@SessionScope
public class UserController {
private int flag = 0;
@RequestMapping("/getUser")
public int getUser(){
return flag++;
}
}
在同一个浏览器上(或者说在同一个Session范围内)多次请求,效果上与Singleton的一样,在一个session生命周期自然结束、清除浏览缓存、不同的浏览器等等操作导致session的结束,再次请求都会获得一个新的实例。
Spring容器通过对整个web应用使用一次bean定义来创建一个bean的新实例。也就是说,该bean的作用域在ServletContext级别,并存储为常规的ServletContext属性。这有点类似于Spring单例bean,但在两个重要方面不同:
它是每个ServletContext的一个单例,而不是每个Spring ‘ApplicationContext’(在任何给定的web应用程序中可能有几个);
它实际上是暴露的,因此可以作为可见的ServletContext属性。
一个web程序会创建唯一一个ServletContext,他的生命周期从启动应用到关闭应用,也就是说,只要你的web服务没挂,请求获得的都是同一个bean实例。
<bean id="appPreferences" class="com.example.AppPreferences" scope="application"/>
@RestController
@Scope("application")
public class ServletController {
private int flag = 0;
@RequestMapping("/get")
public int login(){
return flag++;
}
}
或者
@RestController
@ApplicationScope
public class ServletController {
private int flag = 0;
@RequestMapping("/get")
public int login(){
return flag++;
}
}
Spring IoC容器不仅管理对象(bean)的实例化,还管理协作者(或依赖项)的连接。如果想将(例如)一个HTTP Request作用域的bean注入到另一个生命周期较长的作用域bean中,可以选择注入一个AOP代理来代替该作用域bean。也就是说,需要注入一个代理对象,该对象公开与作用域对象相同的公共接口,但也可以从相关作用域(例如HTTP request)检索实际目标对象,并将方法调用委托给实际对象。