Spring官方文档阅读(四)之浅谈Bean Scope

1.5.Bean Scope

Bean在Spring 3.0之前存在6种作用域,3.0+ 存在7种作用域,多出的一种是线程作用域(Thread Scope)

  1. singleton:(默认)为每个Spring IoC容器将单个bean定义的作用域限定为单个对象实例。
  2. prototype:将单个bean定义的作用域限定为任意数量的对象实例。
  3. request:将单个bean定义的范围限定为单个HTTP请求的生命周期。也就是说,每个HTTP请求都有一个在单个bean定义后面创建的bean实例。仅在可感知网络的Spring上下文中有效ApplicationContext。
  4. session:将单个bean定义的范围限定为HTTP的生命周期Session。仅在web的Spring上下文中有效ApplicationContext。
  5. application:将单个bean定义的作用域限定为的生命周期SerevletContext。仅在web的Spring上下文中有效ApplicationContext。
  6. websocket:将单个bean定义的作用域限定为的生命周期WebSocket。仅在web的Spring上下文中有效ApplicationContext。

1.5.1.Scope说明

Bean的Scope定义,就意味着Bean的生命周期的定义

singleton(单例)

Spring在默认情况下的Scope定义就是singleton;
单例模式下,Spring容器会在创建Bean时,调用缓存,是否存在被创建的Bean,如果存在,调用缓存中的Bean,则不需要进行创建;若不存在,对该Bean进行创建,并将其存储在容器缓存中,也就是这个Bean有且只会被创建一次
在这里插入图片描述

prototype(原型)

对prototype所定义的Bean发起请求时,Bean都会创建一个新的Bean实例;
建议:存在状态的Bean定义为prototype,无状态的Bean定义为singleton
在这里插入图片描述

  • 与其他作用域相比,spring不能管理原型Bean的完整生命周期。
  • 容器只是将原型对象实例化,配置或组装,然后将其交给客户端
  • 用户必须通过客户端代码来清楚原型作用域内的对象,进而释放资源,释放资源可以使用bean后置处理器
  • 从某种角度来看,原型模式,就是java中的new

注意:数据访问对象DAO一般不能配置为原型,因为正常的DAO不拥有任何对话状态

原型bean依赖单例bean存在的问题
默认情况下,单例bean中注入原型bean,单例bean每次调用的都是同一个原型bean;
但是如果需要单例bean每次都是重复获取原型bean的新实例,那么就要使用到方法注入

Request, Session, Application, and WebSocket 作用域

这几个作用域都是在Web环境下使用的,使用前要做一些初始配置

  • 如果是在Spring Web MVC中访问这些模式的bean,实际上是由spring
    DispatcherServlet处理的请求中访问,不需要进行其他设置,因为DispatcherServlet已经公开了所有的相关状态
  • 如果使用的是Servlet 2.5的web容器,请求的进程就在spring DispatcherServlet外部,我们需要自行注册org.springframework.web.context.request.RequestContextListener,如果是Servlet 3.0+,可以通过实现WebApplicationInitializer接口来使用代码的方式来实现注册
<web-app>
    ...
    <listener>
        <listener-class>
            org.springframework.web.context.request.RequestContextListener
        </listener-class>
    </listener>
    ...
</web-app>

如果监听器不能使用,我们可以使用Spring的RequestContextFilter过滤器

<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请求对象绑定到Thread为该请求提供服务的对象。这使得在请求链和会话范围内的Bean可以在调用链的更下游使用。

request作用域

在Spring容器中,在每一次HTTP请求时,都会创建不同的bean对象,所以我们可以对这些Bean对象进行随意的改变其中的状态,其他请求不会受到影响。它们只能作用于单个请求,当请求完成处理时,这个bean会被销毁

Session作用域

该Bean的生命周期,在每次会话中

Application作用域

被Application定义的Bean,表示这个Bean的作用域是在ServletContext,并存储为常规ServletContext属性;与单例模式相类似,但是有两个区别

  • 它是每个ServletContext而不是每个Spring
    ApplicationContext的单例(在一些特定的web应用程序中ServletContext可能是多个的)
  • 它是公开的,因此ServletContext可以看作一个属性

1.5.2.作用域小的Bean依赖作用域大的Bean问题

Spring IoC容器不仅管理Bean的实例化,而且还管理依赖注入之间的连接。
如果我们要将一个request范围的bean注入另一个作用域范围更广的bean中,那么我们可以选择注入AOP代理来代替request bean,这个代理会公开这个request bean的公共接口,我们可以从这个接口中,获取的真正的目标对象,也就是request bean

如何使用代理
使用标签:<aop:scoped-proxy/>

  • 如果是在单例bean下使用,这个单例bean会经过可序列化,然后可以通过反序列化重新获得这个单例bean
  • 如果是原型bean,那么代理上的每个方法每次调用都会导致创建新的目标实例,然后将调用转发到目标实例
<?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/> 
    </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>

除了使用代理以外,我们还可以将注入点声明为ObjectFactory,然后通过getObject()来调用当前实例,不需要保存这个实例

1.5.3.自定义Scope

Bean的作用域是可扩展的,我们可以自定义作用域或者重新定义已有的作用域
创建自定义的scope
要在spring中创建自定义的scope,我们需要实现org.springframework.beans.factory.config.Scope接口,其中有四种方法,可以从作用域中获取对象,删除对象,销毁作用域或者其中对象,返回scope id

使用自定义的scope
在编写了自定义Scope的实现后,将其注册到spring容器中
void registerScope(String scopeName, Scope scope);

此方法在ConfigurableBeanFactory接口上声明,该接口可通过 Spring附带的BeanFactory大多数具体ApplicationContext实现上的属性获得。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值