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

发布时间:2025-12-10 11:22:27 浏览次数:4

1.5.Bean Scope

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

  • singleton:(默认)为每个Spring IoC容器将单个bean定义的作用域限定为单个对象实例。
  • prototype:将单个bean定义的作用域限定为任意数量的对象实例。
  • request:将单个bean定义的范围限定为单个HTTP请求的生命周期。也就是说,每个HTTP请求都有一个在单个bean定义后面创建的bean实例。仅在可感知网络的Spring上下文中有效ApplicationContext。
  • session:将单个bean定义的范围限定为HTTP的生命周期Session。仅在web的Spring上下文中有效ApplicationContext。
  • application:将单个bean定义的作用域限定为的生命周期SerevletContext。仅在web的Spring上下文中有效ApplicationContext。
  • 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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd"><!-- an HTTP Session-scoped bean exposed as a proxy --><bean 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 ><!-- 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实现上的属性获得。

    需要做网站?需要网络推广?欢迎咨询客户经理 13272073477