【Java.Spring.Core】【IoC】Bean 作用域 - Scopes

我们不但可以控制bean的依赖及配置,还可以控制bean的作用域。

Bean作用域 Scope

Spring支持5种bean的作用域,(在web application中可以使用其中的3种):

  • singleton —— 默认为每个IoC容器单例(一个context,一个bean)
  • prototype —— 可以是任意数量的示例
  • request  —— bean的生命周期在一个HTTP request中。即每个Http Request有其自有的bean示例;(该作用域仅适用于基于web的Spring ApplicationContext)
  • session —— bean的生命周期在一个HTTP Session中;(该作用域仅适用于基于web的Spring ApplicationContext)
  • global session —— bean的生命周期在一个全局的HTTP Session中;(适用于portlet context)
  • application —— bean的生命周期在一个ServletContext中;(该作用域仅适用于基于web的Spring ApplicationContext)
  • (在Spring 3.0中,可以使用thread scope,但是默认没有注册该种scope)

singleton

在Spring容器中只有一个共享的bean的单件实例。

单件bean存放在单件benas的缓存中;在创建之后请求访问该bean将直接返回缓存的bean对象。


Spring中的单件概念与设计模式中的不同,设计模式中的对象作用域是hard-codes的,保证在每个特定的ClassLoader中只有一个类的实例被创建。而Spring容器中的单件为每个容器拥有一个bean的实例

单件作用域是Spring的默认作用域;可以在XML中如下配置单件:

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

<!-- the following is equivalent, though redundant (singleton scope is the default) -->
<bean id="accountService" class="com.foo.DefaultAccountService" scope="singleton"/>

prototype

使用prototype作用域,则每次该bean,都会生成一个该bean的新的实例。

常见的使用规则是:对于有状态的bean,使用prototype;对于无状态的bean,使用singleton


在XML中,如下配置prototype:

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


与其他的scope不同的是,Spring不会负责管理prototype scope的生命周期;Spring容器实例化,配置,组装prototype bean,然后将其交给客户程序去处理,而不会在容器中继续维护该实例的记录。

因此,虽然所有的生命周期初始化回调函数会在所有的scope上被调用,但是,prototype的destruction 生命周期回调函数不会被调用。客户代码必须负责清理prototype scope的对象,并释放prototype对象持有的资源。为了使Spring容器释放prototype bean持有的资源,可以使用自定义的 bean post-processor,其持有一个需要清理的bean的引用。

Singleton bean中的prototype dependencies

当在singleton中使用prototype的依赖时,依赖在初始化的时候被解析。因此,当prototype bean被注入singleton bean中时,一个新的prototype bean被实例化并注入给singleton bean中。该prototype bean为该单件bean的prototype的唯一示例。


Request, session, global session, application

这些scope只可以使用在基于web的Spring ApplicationContext实现中(如XmlWebApplicationContext)。如果在普通的Spring IoC容器中使用这些scope,则会抛出一个IllegalStateException异常(未知的bean scope)

初始化web配置

为了支持request, session, global session scope的bean,需要在bean定义之前进行一些配置(这些初始化的设置在standard scope中时是不需要的)


这些初始化设置依赖于特定的Servlet环境:

如果在Spring Web MVC中的访问request scope的bean,由DispatcherServelt或者DispatcherPortlet来完成

如果使用Servlet 2.5 web 容器,在Spring DispatcherServlet外处理的request,需要注册org.springframework.web.context.request.RequestContextLinstener, ServletRequestListener。

对于Servlet3.0+,可以在WebApplicationInitializer接口中编程完成。

对于更旧版本的web容器,在web.xml中添加下列的声明:

<web-app>
    ...
    <listener>
        <listener-class>
            org.springframework.web.context.request.RequestContextListener
        </listener-class>
    </listener>
    ...
</web-app>


如果listener的设置有问题的话,可以考虑使用RequestContextFilter,filter mapping依赖于具体的使用环境:

<web-app>
    ...
    <filter>
        <filter-name>requestContextFilter</filter-name>
        <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>requestContextFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    ...
</web-app>


DispatcherServelt, RequestContextListener, RequestContextFilter做的事情是一样的,即将HTTP Request对象绑定到处理该request的Thread,这使得request session作用域的bean在之后的调用链中可用

Request scope

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


Spring容器在每一个HTTP Request中创建一个该bean的新的实例。这些bean的实例为每个独立的quest所拥有。当request完成处理的时候,request scope bean将会被回收。

Session scope

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

在每一个HTTP Session中,Spring容器创建了一个session scope的bean的示例。Request与Session scope的bean的行为类似

Global session scope

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


global session scope与session scope类似,其仅应用在基于portlet的web application中。

如果在标准的基于 servlet 中web application中,定义了global session scope的 beans,实际上使用的是 session scope。

Application scope

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

application scope bean的作用范围为整个web application,该bean被存储为ServletContext的一个属性

application scope bean 与 Spring 单例bean有些相似,但是有两点不同

  • application scope bean是每个ServletContext中一个单件,而不是每个Spring Application Context中一个
  • application scope bean为每个ServletContext的属性

scoped beans作为其他bean的依赖

对于 singleton 或者 prototype scope bean,如果其作为其他bean的依赖,不需要使用 <aop:scoped-proxy/>.

当使用request- session- globalSession- scoped 的beans作为其他bean的依赖,按如下配置:

<bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
    <aop:scoped-proxy/>
</bean>
<bean id="userManager" class="com.foo.UserManager">
    <property name="userPreferences" ref="userPreferences"/>
</bean>

自定义scopes

我们可以自定义scope,甚至可以重载现存的scope。

创建自定义scope

需要实现 org.springframework.beans.factory.config.Scope接口。

Scope接口有4个方法用于获取对象,移除对象,销毁对象。

使用自定义scope

使用下列方法在Spring容器中注册自定义Scope:

void registerScope(String scopeName, Scope scope);

该方法位于ApplicationContext的实现中。

例如:

Scope threadScope = new SimpleThreadScope();
beanFactory.registerScope("thread", threadScope);

<bean id="..." class="..." scope="thread">

除了使用编程方法注册scope,可以使用CustomScopeConfigurer类进行scope的注册:

<?xml version="1.0" encoding="UTF-8"?>
<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">

    <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
        <property name="scopes">
            <map>
                <entry key="thread">
                    <bean class="org.springframework.context.support.SimpleThreadScope"/>
                </entry>
            </map>
        </property>
    </bean>

    <bean id="bar" class="x.y.Bar" scope="thread">
        <property name="name" value="Rick"/>
        <aop:scoped-proxy/>
    </bean>

    <bean id="foo" class="x.y.Foo">
        <property name="bar" ref="bar"/>
    </bean>

</beans>





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值