我们知道,Spring
容器中的bean
对象有不同的作用域,对于一个Web
应用中,常见的作用域有:singleton
,prototype
,request
,session
,application
。对于一个bean
定义,如果没有特殊指定,其缺省的作用域为singleton
。
比如我们通过注解@Service
,@Controller
,@Component
,@Repository
所定义的组件bean
,缺省都是singleton
作用域。
对于以上这些作用域,它们的具体含义如下:
作用域 | 含义描述 |
---|---|
singleton |
整个Spring IoC 容器内只有一个这样的bean ,生成后一直保持到容器销毁 |
application |
整个ServletContext 视为一个应用,在这个应用内只有一个这样的bean ,创建之后一直保持到该ServletContext 销毁 |
session |
整个HTTP Session 对应只有一个这样的bean ,创建之后一直保持到该HTTP session 被销毁 |
request |
整个HTTP request 请求处理过程对应只有一个这样的bean ,创建之后一直保持到该HTTP request 处理完被销毁 |
prototype |
每次从容器获取该bean 都会得到一个新的实例,会被如何保持,会被保持多长时间,都由使用者决定,容器不再管理 |
对于上面的这些作用域,singleton
/prototype
使用于任何类型的Spring
应用,而application
/session
/request
仅仅针对Spring Web
应用。
另外从这些作用域的长短或者说对应bean
的可见性上来看,可以这么排序 :
singleton
>application
>request
>session
这里 prototype
并没有被放到排序里面,原因是容器只负责这类bean
的创建,而至于这类bean
会被如何保持,保持多长时间,都由使用者自行决定,所以这里的排序没有考虑它。
根据上面这些作用域的定义,不难理解,将一个较大作用域的bean
注入到一个较小作用域的bean
中是可行的。但是,是否可以将一个较小作用域的bean
注入到一个较大作用域的bean
中呢?仅仅从概念上理解,似乎是行不通的。但结合各种实现技术,Spring
做到了这一点。简单点讲,Spring
典型的做法是,当要将以一个小作用域的bean
注入到一个大作用域的bean
中时,Spring
注入的其实是一个代理对象,可以理解该代理对象的作用域级别一定不小于注入目标bean
的作用域,并且该代理对象会在使用者想获取小作用域的bean
时,动态地分析当前的运行时上下文,获取该小作用域bean
给使用者。典型的一个例子,可以参考在singleton
Web
控制器bean
组件中注入request
级别作用域HttpServletRequest
bean
的例子。