Spring框架Bean作用域

Spring框架现有的Bean作用域

( 1 ) singleton :默认的作用域,仅为每个 Bean 对象创建一个实例。

( 2 ) prototype :可以根据需要为每个 Bean 对象创建多个实例。

( 3 ) request :为每个 HTTP 请求创建它自有的一个 Bean 实例,仅在 Web 相关的 ApplicationContext 中生效。

( 4 ) session :为每个 HTTP 会话创建一个实例,仅在 Web 相关的 ApplicationContext 中生效。

( 5 ) global session :为每个全局的 HTTP 会话创建一个实例。一般仅在 porlet上下文中使用生效。同时仅在 Web 相关的 ApplicationContext 中生效。

( 6 ) application :为每个 ServletContext 创建一个实例。仅在 Web 相关的 ApplicationContext 中生效。

1 singleton 作用域

当一个 bean的 作用域 设置为 singleton, 那么Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。换言之,当把一个bean定义设置为singleton作用域时,Spring IOC容器只会创建该bean定义的唯一实例。这个单一实例会被存储到单例缓存(singleton cache)中,并且所有针对该bean的后续请求和引用都将返回被缓存的对象实例,这里要注意的是singleton作用域和GOF设计模式中的单例是完全不同的, GoF 描述的是,指定的类在每个 ClassLoader 中仅会创建一个实例,并且是通过硬编码来完成的。而 Spring 中的单例最好解释为每个容器仅有 Bean 的一个实例。这就意味着,如果在 Spring 容器中定义一个 Bean ,容器将会根据定义为 Bean创建仅仅一个实例。在 Spring 中, singleton 作用域是默认的作用域。


2 prototype 作用域

非单例的 prototype 作用域,在每次请求一个指定 Bean 的时候都会创建一个新的实例。通常,对于具有状态的 Bean 使用 prototype ,对于无状态的 Bean 使用 singleton。

下面的例子将一个 Bean 定义为 prototype :

<bean id="accountService" class="com.foo.DefaultAccountService" scope="prototype"/>

与其它作用域相比, Spring 不会管理一个 prototype 作用域 Bean 的完整生命周期。容器实例化、配置和组装一个 prototype 实例,然后转交给客户端,不再继续跟踪那个 prototype 实例。因此,处于初始化生命周期的回调方法在所有作用域下都会被调用,而在 prototype 作用域下,析构生命周期回调不会被调用。客户端代码必须清理 prototype 作用域对象,释放对象所持有的昂贵的资源。

当单例 Bean 依赖 prototype 类型的 Bean 时,注意这种依赖是在实例化的时候解析的,一个新的 prototype 类型的 Bean 会被实例化然后注入到单例 Bean 中,因此这个prototype 类型的 Bean 对于这个单例 Bean 而言只有一个,而不是我们所认为的为每次请求单例 Bean 会创建一个新的 prototype 类型的 Bean 。如果要为每次请求单例 Bean 创建一个新的 prototype 类型的 Bean ,就不能这样做了,因为注入只会发生一次,即在 Spring 容器在实例化单例和解析依赖的时候。若需要这样的功能,可以参考方法注入 。

3 request, session, global session 和 application 作用域

request, session 和 global session 作用域仅在使用 Web 相关的 ApplicationContext实现(比如 XmlWebApplicationContext )时才会有用。如果使用平常的 Spring IoC容器(比如 ClassPathXmlApplicationContext ),将会抛出 IllegalStateException 异常。

为了支持 request, session 和 global session 作用域,在定义 Bean 之前需要做一些必要的配置。具体如何完成这样的配置决定于特定的 Servlet 环境。如果使用的是 Spring Web MVC ,通过 DispatcherServlet 或者 DispatcherPortlet 来执行请求,不需要做任何设置, DispatcherServlet 或者 DispatcherPortlet 已经暴露了所有相关的状态。

如果使用的是 Servlet2.5 的 Web 容器,且使用的是 DispatcherServlet 之外的 Servlet (比如 Struts )来执行请求,那么就需要注册 org.springframework.web.context.request.RequestContextListener ServletRequestListener 。对于 Servlet3.0+ ,可以通过 WebApplicationInitializer 接口编码实现这样的功能。

3.1 request 作用域

请看如下示例:

<bean id="loginAction" class="com.foo.LoginAction" scope="request"/>

Spring 容器为每个 HTTP 请求创建一个新的 loginAction 实例,这个实例的状态可以根据需要进行修改,而不会影响到其它请求中创建的实例。当请求执行完毕时,那么这个实例就会被遗弃。

3.2 session 作用域

请看如下示例:

<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>

Spring 容器会为每个会话创建一个 userPreferences 实例。跟 request 作用域类似,实例的状态可以根据需要进行修改,不会影响到其它会话中创建的实例。

3.3 global session 作用域

global session 作用域跟 session 作用域类似,仅应用于基于 portlet 的上下文。

3.4 application 作用域

请看如下示例:

<bean id="appPreferences" class="com.foo.AppPreferences" scope="application"/>

Spring 会为整个 Web 应用创建一个 appPreferences 实例,作为 ServletContext 的一个属性存储着。它跟 Spring 的单例 Bean 有点像,但也有不同,它在每个 ServletContext 中是单例的,而非 Spring 的 ApplicationContext 。

3.5 作用域 Bean 依赖

如果想把一个 HTTP request 作用域的 Bean 注入到另一个长周期作用域的 Bean中,就需要选择注入一个 AOP 代理来替换这个 request 作用域 Bean 。也就是,需要注入一个代理对象,这个代理对象暴露了 request 作用域 Bean 的公共接口,可以查找到真实的目标对象,然后将方法调用委托到真实的对象上面。比如在单例 Bean 中注入一个会话 Bean ,若不使用代理,那么在会话 Bean 失效之后,单例 Bean 将不能再获取到会话 Bean 。若使用代理,那么代理对象将从作用域机制中找到对应的 Bean 。

示例如下:


<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!—一个HTTP 会话作用域的Bean 作为代理暴露出去-->
    <bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
        <!—指示容器代理这个Bean -->
        <aop:scoped-proxy/>
    bean>
    <!—一个单例Bean注入一个代理Bean -->
    <bean id="userService" class="com.foo.SimpleUserService">
        
        <property name="userPreferences" ref="userPreferences"/>
    bean>
beans>

你可能感兴趣的:(Spring)