AI智能
改变未来

Spring系列8:bean的作用域


本文内容

  1. bean定义信息的意义
  2. 介绍6种bean的作用域

bean定义信息的意义

Spring中区分下类、类定义信息,类实例对象的概念?不容易理解,以餐馆中点炒饭为例。

类: 相当于你看到菜单上炒饭这个菜品,有这个菜。

类定义信息:相当于炒饭的烹饪法,烹饪法只有一份

类实例对象: 相当于按照上面烹饪法炒出来的一份炒饭,可以炒分多份出来。

Spring容器中创建了一个类定义信息的,就可以根据这个定义信息来创建个类实例对象出来,这个理解了很关键。Spring中不仅可以控制 bean 对象中的各种依赖项和配置值,还可以控制 bean 额作用范围。

介绍6种bean的作用域

Spring Framework 支持6个bean的作用域,其中4个仅在web类型的

ApplicationContext

中可用。详细见下表

作用域 描述
singleton (默认)将单个 bean 定义限定为每个 Spring IoC 容器的单个对象实例。
prototype 将单个 bean 定义限定为任意数量的对象实例
request 将单个 bean 定义限定为单个 HTTP 请求的生命周期。也就是说,每个 HTTP 请求都有自己的 bean 实例,该实例是在单个 bean 定义的后面创建的。仅在web类型的

ApplicationContext

有效。

session 将单个 bean 定义限定为 HTTP 会话的生命周期。仅在web类型的

ApplicationContext

有效。

application 将单个 bean 定义限定为 ServletContext 的生命周期。仅在web类型的

ApplicationContext

有效。

websocket 将单个 bean 定义限定为 WebSocket 的生命周期。仅在web类型的

ApplicationContext

有效。

从 Spring 3.0 开始,线程范围可用,但默认情况下未注册。

SimpleThreadScope

感兴趣可以详细看下面自定义作用域。

singleton

只有一个单例 bean 的共享实例被管理,并且所有对具有与该 bean 定义匹配的一个或多个 ID 的 bean 的请求都会导致 Spring 容器返回一个特定的 bean 实例。"蝎子粑粑独一份"。注意是一个IoC容器内。

prototype

原型作用域下每次容器都会创建一个新的 bean 实例。通常来说,对有状态 bean适合使用原型,对无状态 bean适合使用单例。

下面的配置节指定了bean的作用域是原型的。

<bean id="accountService" class="x.y.z.AccountService" scope="prototype"/>

与其他范围相比,Spring 不管理原型 bean 的完整生命周期。容器实例化、配置和以其他方式组装原型对象并将其传递给客户端,由客户端去管理。bean生命周期后面介绍。

request, session, application, webSocket

这4个在web的应用上下文中使用的作用域,暂不展开讲,留给后面写spring mvc 专门讲。

自定义作用域和使用

如何自定义?

可以通过实现

org.springframework.beans.factory.config.Scope

自定义作用域。

Scope

接口有四种方法可以从作用域中获取对象,将它们从作用域中移除,并让它们被销毁。

package org.springframework.beans.factory.config;public interface Scope {// 从底层范围返回具有给定名称的对象Object get(String name, ObjectFactory<?> objectFactory);// 从底层范围中删除具有给定的对象Object remove(String name);// 注册要在作用域中指定对象的销毁时执行的回调void registerDestructionCallback(String name, Runnable callback);// 省略}

打铁要趁热,直接上

SimpleThreadScope

的源码,解析下线程级别作用域是如何实现的。

package org.springframework.context.support;public class SimpleThreadScope implements Scope {private static final Log logger = LogFactory.getLog(SimpleThreadScope.class);// 1 bean是存放在ThreadLocal中的 绑定了当前线程private final ThreadLocal<Map<String, Object>> threadScope =new NamedThreadLocal<Map<String, Object>>("SimpleThreadScope") {@Overrideprotected Map<String, Object> initialValue() {return new HashMap<>();}};// 2 查ThreadLocal,有对应bean就直接返回,没有就创建一个放入ThreadLocal,在返回@Overridepublic Object get(String name, ObjectFactory<?> objectFactory) {Map<String, Object> scope = this.threadScope.get();Object scopedObject = scope.get(name);if (scopedObject == null) {scopedObject = objectFactory.getObject();scope.put(name, scopedObject);}return scopedObject;}// 3 从ThreadLocal中移除bean@Override@Nullablepublic Object remove(String name) {Map<String, Object> scope = this.threadScope.get();return scope.remove(name);}// 4 销毁回调@Overridepublic void registerDestructionCallback(String name, Runnable callback) {logger.warn("SimpleThreadScope does not support destruction callbacks. " +"Consider using RequestScope in a web environment.");}@Override@Nullablepublic Object resolveContextualObject(String key) {return null;}@Overridepublic String getConversationId() {return Thread.currentThread().getName();}}

如何使用?

  1. 先将自定义的scope注入到容器中

    编码的方式注册:

    ConfigurableBeanFactory

    接口提供了

    registerScope

    来注册自定义的scope。

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

    配置文件方式的注册: 使用

    CustomScopeConfigurer

    以声明方式进行注册

    <?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"><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></beans>
  2. bean配置中使用

    使用方式普通的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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttps://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>

总结

本文Spring中的7种作用域,以及如何自定义作用域并使用。下一篇介绍基于注解的Spring容器配置。

知识分享,转载请注明出处。学无先后,达者为先!

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » Spring系列8:bean的作用域