Spring 框架支持六种作用域,其中四种仅在使用 Web-aware ApplicationContext 时可用。 此外,你还可以创建自定义作用域。
下表描述了支持的作用域:
Scope
Description
singleton
(Default) Scopes a single bean definition to a single object instance for each Spring IoC container.
prototype
Scopes a single bean definition to any number of object instances.
request
Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext .
session
Scopes a singe bean definition to the lifecycle of an HTTP Session . Only valid in the context of a web-aware Spring ApplicationContext .
application
Scopes a single bean definition to the lifecycle of a ServletContext . Only valid in the context of a web-aware Spring ApplicationContext .
websocket
Scopes a single bean definition to the lifecycle of a WebSocket . Only valid in the context of a web-aware Spring ApplicationContext .
Spring 框架中的单例 Bean 的概念与设计模式中定义的单例模式有所不同。设计模式中的单例模式将对象的作用域硬编码为每个 ClassLoader 仅创建一个特定类的实例。Spring 中单例的作用域最好描述为每个容器和每个 Bean。这意味着,如果你在一个 Spring 容器中为特定类定义了一个 bean,Spring 容器将只创建一个该 bean definition 所定义类的实例。
要在 XML 中将一个 bean 定义为 Singleton,你可以按照以下示例定义一个 bean:
1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"><beanid="accountService"class="com.something.DefaultAccountService"/><!-- the following is equivalent, though redundant (singleton scope is the default) --><beanid="accountService"class="com.something.DefaultAccountService"scope="singleton"/></beans>
要在 Spring Boot 中将一个 bean 定义为 Singleton,你可以按照以下示例定义一个 bean:
1
2
3
4
5
6
7
8
9
importorg.springframework.beans.factory.config.ConfigurableBeanFactory;importorg.springframework.context.annotation.Scope;importorg.springframework.stereotype.Component;@Component@Scope(value=ConfigurableBeanFactory.SCOPE_SINGLETON)publicclassDefaultAccountService{// some definition}
由于单例作用域是 Spring 默认的作用域,因此,对于作用域需要定义为 Singleton 的 bean,无需添加 @Scope 注解。
作用域 request、session、application、websocket 仅在 Web Application Context 中可用(例如,XmlWebApplicationContext),如果你尝试在常规的 Spring IoC 容器(例如,ClassPathXmlApplicationContext )中使用这些作用域,将会抛出 IllegalStateException 异常,报告未知的 Bean 作用域。注:常规 Spring Boot 工程可用。
importorg.springframework.context.annotation.Scope;importorg.springframework.context.annotation.ScopedProxyMode;importorg.springframework.stereotype.Component;importorg.springframework.web.context.WebApplicationContext;@Component@Scope(value=WebApplicationContext.SCOPE_REQUEST,proxyMode=ScopedProxyMode.TARGET_CLASS)publicclassHelloMessageGenerator{// some definition}
proxyMode 属性是必要的,因为在实例化 Web Application Context 时,没有活动的请求。Spring 创建一个代理来作为注入依赖,并在需要时在请求中实例化目标 Bean。
此外,还可以使用一个组合的注解 @RequestScope 来充当上述定义的快捷方式(推荐):
1
2
3
4
5
6
7
8
importorg.springframework.stereotype.Component;importorg.springframework.web.context.annotation.RequestScope;@Component@RequestScopepublicclassHelloMessageGenerator{// some definition}
Session Scope
我们也可以用相似的方式定义作用域 session 的 Bean:
1
2
3
4
5
6
7
8
9
10
importorg.springframework.context.annotation.Scope;importorg.springframework.context.annotation.ScopedProxyMode;importorg.springframework.stereotype.Component;importorg.springframework.web.context.WebApplicationContext;@Component@Scope(value=WebApplicationContext.SCOPE_SESSION,proxyMode=ScopedProxyMode.TARGET_CLASS)publicclassHelloMessageGenerator{// some definition}
同样的,也可以用一个组合注解 @SessionScope 来简化定义:
1
2
3
4
5
6
7
8
importorg.springframework.stereotype.Component;importorg.springframework.web.context.annotation.SessionScope;@Component@SessionScopepublicclassHelloMessageGenerator{// some definition}
importorg.springframework.context.annotation.Scope;importorg.springframework.context.annotation.ScopedProxyMode;importorg.springframework.stereotype.Component;importorg.springframework.web.context.WebApplicationContext;@Component@Scope(value=WebApplicationContext.SCOPE_APPLICATION,proxyMode=ScopedProxyMode.TARGET_CLASS)publicclassHelloMessageGenerator{// some definition}
以简洁的方式(@ApplicationScope) 定义:
1
2
3
4
5
6
7
8
importorg.springframework.stereotype.Component;importorg.springframework.web.context.annotation.ApplicationScope;@Component@ApplicationScopepublicclassHelloMessageGenerator{// some definition}
@Component@Scope(scopeName="websocket",proxyMode=ScopedProxyMode.TARGET_CLASS)publicclassMyBean{@PostConstructpublicvoidinit(){// Invoked after dependencies injected}// ...@PreDestroypublicvoiddestroy(){// Invoked when the WebSocket session ends}}@ControllerpublicclassMyController{privatefinalMyBeanmyBean;@AutowiredpublicMyController(MyBeanmyBean){this.myBean=myBean;}@MessageMapping("/action")publicvoidhandle(){// this.myBean from the current WebSocket session}}
Custom Scopes
除了以上 Spring 已经定义好的 Scope 之外,你也可以定义自己的 Scope。如果你有兴趣,请参考官方文档
。本文不再赘述。
@Component@Scope("prototype")publicclassPrototypeBean{publicObjectexecute(){//...}}publicclassSingletonBean{privatePrototypeBeanprototypeBean;@AutowiredpublicSingletonBean(PrototypeBeanprototypeBean){// Noncompliant, the same instance of PrototypeBean is used for each bean request.this.prototypeBean=prototypeBean;}publicObjectprocess(){returnprototypeBean.execute();}}
@Component@Scope(value=WebApplicationContext.SCOPE_REQUEST,proxyMode=ScopedProxyMode.TARGET_CLASS)publicclassRequestBean{//...}publicclassSingletonBean{@AutowiredprivatefinalRequestBeanrequestBean;// Noncompliant, the same instance of RequestBean is used for each HTTP request.publicRequestBeangetRequestBean(){returnrequestBean;}}