Spring Framework Documentation-1.5

1.5 bean scope

bean定义是recipe很重要,因为它意味着,与类一样,您可以从一个配方创建许多对象实例。您不仅可以控制要插入到由特定bean定义创建的对象中的各种依赖项和配置值,还可以控制由特定bean定义创建的对象的范围。这种方法功能强大且灵活,因为您可以选择通过配置创建的对象的范围,而不必在Java类级别上考虑对象的范围。Spring框架支持六个作用域,其中四个只有在使用web感知的应用程序上下文时才可用。您还可以创建自定义范围。

Scope Description

singleton 为每个Spring IoC容器将单个bean定义限定为单个对象实例

prototype 将单个bean定义的范围限定为任意数量的对象实例。

request 将单个bean定义的范围限定为单个HTTP请求的生命周期。也就是说,每个HTTP请求都有自己的bean实例,该实例是在单个bean定义的基础上创建的。仅在可感知web的Spring ApplicationContext上下文中有效。

session 将单个bean定义的范围限定为HTTP会话的生命周期。仅在可感知web的Spring ApplicationContext上下文中有效。

application 将单个bean定义的范围限定为ServletContext的生命周期。仅在可感知web的Spring ApplicationContext上下文中有效。

websocket 将单个bean定义的范围限定为WebSocket的生命周期。仅在可感知web的Spring ApplicationContext上下文中有效。

1.5.1 单例的范围

只管理一个单例bean的一个共享实例,所有对ID或ID匹配该bean定义的bean的请求都会导致Spring容器返回该特定的bean实例。Spring的单例bean概念不同于Gang of Four (GoF)模式书中定义的单例模式。GoF单例硬编码对象的范围,这样每个类加载器只能创建一个特定类的一个实例。Spring单例的范围最好描述为每个容器和每个bean。这意味着,如果您在单个Spring容器中为特定类定义一个bean,那么Spring容器将创建由该bean定义定义的类的一个且仅一个实例。单例范围是Spring中的默认范围。

1.5.2 Prototype 范围

bean部署的非单例原型范围会在每次发出对特定bean的请求时创建一个新的bean实例。也就是说,bean被注入到另一个bean中,或者您通过容器上的getBean()方法调用请求它。通常,您应该为所有有状态bean使用原型范围,为无状态bean使用单例范围。

与其他作用域不同,Spring不管理Prototype bean的完整生命周期。容器实例化、配置和以其他方式组装原型对象并将其传递给客户机,而不需要该原型实例的进一步记录。因此,虽然初始化生命周期回调方法在所有对象上都被调用,但在Prototype 的情况下,配置的销毁生命周期回调并不被调用。

1.5.3. Singleton Beans with Prototype-bean Dependencies

当您使用依赖于原型bean的单作用域bean时,请注意依赖项是在实例化时解析的。因此,如果将一个原型作用域bean注入到一个单例作用域bean中,就会实例化一个新的原型bean,然后将依赖注入到单例bean中。原型实例是惟一提供给单例作用域bean的实例。

但是,假设您希望单例作用域bean在运行时重复获取原型作用域bean的新实例。您不能依赖—将一个原型作用域bean注入到您的单例bean中,因为这种注入只发生一次,当Spring容器实例化单例bean并解析和注入它的依赖项时。如果在运行时不止一次需要原型bean的新实例,

1.5.4. Request, Session, Application, and WebSocket Scopes

仅仅在使用 web-aware的spring ApplicationCintext 的实现时,才会使用这些Scope,如果和 IOC 容器一起使用你就会报 IllegalStateException

初始化web配置

除了 singleton与prototype,别的scope都需要在在bean定义之前进行设置。使用Spring Web MVC ,即用DispatcherServlet,请求,则不需要设置,因为其公开所有状态。

使用Servlet 2.5 容器(JSF or Struts),需注册 org.springframework.web.context.request.RequestContextListener``ServletRequestListener

Servlet 3.0+ 容器,WebApplicationInitializerinterface 编程

更老的。。。配置一个web.xml文件,

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

listener 设置有问题,可能是 Spring’s RequestContextFilter,filter 要根据web app环境,根据需求配置。例如;

<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>

DispatcherServlet、RequestContextListener和RequestContextFilter都做完全相同的事情,即将HTTP请求对象绑定到服务该请求的线程。

Request scope

xml配置方式:

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

注解配置方式:

@RequestScope
@Component
public class LoginAction {
    // ...
}

Spring容器通过为每个HTTP请求使用LoginAction bean定义来创建LoginAction bean的新实例。loginAction bean的作用域在HTTP请求级别。您可以随意更改创建的实例的内部状态,因为从相同的loginAction bean定义创建的其他实例在状态中看不到这些更改.针对单个请求,请求结束。

Session Scope

xml配置方式:

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

注解配置方式:

@SessionScope
@Component
public class UserPreferences {
    // ...
}

Spring容器通过为单个HTTP会话的生命周期使用UserPreferences bean定义来创建UserPreferences bean的新实例

HTTP Session level

针对单个http session,内部按需更改。session结束,scope结束

Application Scope
<bean id="appPreferences" class="com.something.AppPreferences" scope="application"/>
@ApplicationScope
@Component
public class AppPreferences {
    // ...
}

整个web app 创建域

ServletContext level 并存储 ServletContext 属性

It is a singleton per ServletContext, not per Spring ‘ApplicationContext’ (for which there may be several in any given web application),它实际上是公开的,因此作为ServletContext属性可见。

Scoped Beans as Dependencies

IOC管理bean和依赖关系,如果想注入request-scope到更高的scope,需要注入AOP proxy代替作用域的bean,需要注入一个代理对象,它公开与作用域对象相同的公共接口,但也可以从相关作用域(例如HTTP request)检索实际目标对象,并将委托方法调用注入到实际对象

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- an HTTP Session-scoped bean exposed as a proxy -->
    <bean id="userPreferences" class="com.something.UserPreferences" scope="session">
        <!-- instructs the container to proxy the surrounding bean -->
        <aop:scoped-proxy/> <!--proxy位置 -->
    </bean>

    <!-- a singleton-scoped bean injected with a proxy to the above bean -->
    <bean id="userService" class="com.something.SimpleUserService">
        <!-- a reference to the proxied userPreferences bean -->
        <property name="userPreferences" ref="userPreferences"/>
    </bean>
</beans>

因此,在将请求和会话范围的bean注入协作对象时,需要以下(正确和完整的)配置

<bean id="userPreferences" class="com.something.UserPreferences" scope="session">
    <aop:scoped-proxy/>
</bean>

<bean id="userManager" class="com.something.UserManager">
    <property name="userPreferences" ref="userPreferences"/>
</bean>
Choosing the Type of Proxy to Create

默认情况下,当Spring容器为用<aop:scope -proxy/>元素标记的bean创建代理时,将创建一个基于cglib的类代理。CGLIB代理只拦截公共方法调用。

也可以使用jdk动态代理:

<!-- DefaultUserPreferences implements the UserPreferences interface -->
<bean id="userPreferences" class="com.stuff.DefaultUserPreferences" scope="session">
    <!--配置这个为false-->
    <aop:scoped-proxy proxy-target-class="false"/>
</bean>

<bean id="userManager" class="com.stuff.UserManager">
    <property name="userPreferences" ref="userPreferences"/>
</bean>

使用jdk不需要额外的库,但需要实现接口,并ref这个bean,cglib需要额外的库

1.5.5 Custom Scopes

可以定义自己的Scope,甚至重新定义已经存在的Scope(除了singleton与prototype)。

Creating a Custom Scope

To integrate your custom scopes into the Spring container, you need to implement theorg.springframework.beans.factory.config.Scope interface,

The Scope interface has four methods to get objects from the scope, remove them from the scope, and let them be destroyed

returns the object from the underlying scope:

Object get(String name, ObjectFactory objectFactory)

removes the session-scoped bean from the underlying session

Object remove(String name)

The following method registers the callbacks the scope should execute when it is destroyed or when the specified object in the scope is destroyed:(销毁反馈)

void registerDestructionCallback(String name, Runnable destructionCallback)

obtains the conversation identifier(每个session的标识符) for the underlying scope:

String getConversationId()
Using a Custom Scope

先在容器中注册

void registerScope(String scopeName, Scope scope);

声明在ConfigurableBeanFactory ,可以通过聚合了ApplicationContext的BeanFactory property 获得

scopeName是唯一关联scope的名称,scope为自定义的作用域

例如:

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

创建自定义的bean

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

第二种方式注册(CustomScopeConfigurer class通过这个):

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://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="thing2" class="x.y.Thing2" scope="thread">
        <property name="name" value="Rick"/>
        <aop:scoped-proxy/>
    </bean>

    <bean id="thing1" class="x.y.Thing1">
        <property name="thing2" ref="thing2"/>
    </bean>

</beans>

当您在FactoryBean实现中放置<aop:scope -proxy/>时,受作用域限制的是工厂bean本身,而不是getObject()返回的对象。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值