专注Java教育14年 全国咨询/投诉热线:400-8080-105
动力节点LOGO图
始于2009,口口相传的Java黄埔军校
首页 hot资讯 Spring作用域的快速指南

Spring作用域的快速指南

更新时间:2022-12-05 11:06:49 来源:动力节点 浏览732次

1. 概述

在这个Spring教程中,我们将了解不同类型的bean Spring框架的范围。

bean的范围定义bean的生命周期和能见度的情况下我们使用它。

最新版本的Spring框架定义了6种范围:

单例

原型

请求

会话

应用程序

websocket

最后四范围所提到的,请求、会话,应用程序和websocket,只有在理解网络应用程序可用。

2. 单例对象范围

当我们使用单例范围定义bean,容器创建bean的一个实例;所有bean名称的请求将返回相同的对象,这是缓存。任何修改对象将反映在所有bean的引用。这个范围是默认值如果没有指定其他范围。

让我们创建一个实体来例证了范围的概念:

public class Person {
    private String name;
    // standard constructor, getters and setters
}

之后,我们定义的bean singleton范围通过使用@ scope注释:

@Bean
@Scope("singleton")
public Person personSingleton() {
    return new Person();
}

我们也可以使用一个常数,而不是字符串值在以下方式:

@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)

现在我们可以继续编写一个测试表明,两个对象指的是相同的bean将有相同的价值观,即使只有一个人改变他们的国家,他们都是引用同一个bean实例:

private static final String NAME = "John Smith";
@Test
public void givenSingletonScope_whenSetName_thenEqualNames() {
    ApplicationContext applicationContext = 
      new ClassPathXmlApplicationContext("scopes.xml");
    Person personSingletonA = (Person) applicationContext.getBean("personSingleton");
    Person personSingletonB = (Person) applicationContext.getBean("personSingleton");
    personSingletonA.setName(NAME);
    Assert.assertEquals(NAME, personSingletonB.getName());
    ((AbstractApplicationContext) applicationContext).close();
}

作用域。xml文件在这个例子中应该包含的xml定义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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="personSingleton" class="org.baeldung.scopes.Person" scope="singleton"/>    
</beans>

3.原型范围

原型的bean将返回一个不同的实例范围每次请求的容器。它通过设置值定义原型在bean定义:@ scope注释

@Bean
@Scope("prototype")
public Person personPrototype() {
    return new Person();
}

我们还可以使用一个常数如单例的范围:

@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)

现在我们将编写一个类似的测试,显示了两个对象请求与原型相同的bean名称范围。他们会有不同的国家不再是指相同的bean实例:

private static final String NAME = "John Smith";
private static final String NAME_OTHER = "Anna Jones";
@Test
public void givenPrototypeScope_whenSetNames_thenDifferentNames() {
    ApplicationContext applicationContext = 
      new ClassPathXmlApplicationContext("scopes.xml");
    Person personPrototypeA = (Person) applicationContext.getBean("personPrototype");
    Person personPrototypeB = (Person) applicationContext.getBean("personPrototype");
    personPrototypeA.setName(NAME);
    personPrototypeB.setName(NAME_OTHER);
    Assert.assertEquals(NAME, personPrototypeA.getName());
    Assert.assertEquals(NAME_OTHER, personPrototypeB.getName());
    ((AbstractApplicationContext) applicationContext).close();
}

作用域。xml文件类似于前一节中给出的一个而添加xml定义的bean原型范围:

<bean id="personPrototype" class="org.baeldung.scopes.Person" scope="prototype"/>

4. 认识到网络范围

正如前面提到的,有四个额外的范围,只有在理解网络应用程序上下文。我们在实践中很少使用这些。

请求范围为一个HTTP请求,创建一个bean实例在会话范围创建一个HTTP会话bean实例。

应用范围创建bean实例的生命周期ServletContext,和websocket创建为一个特定的websocket会话范围。

让我们创建一个类实例化bean的使用:

public class HelloMessageGenerator {
    private String message;    
    // standard getter and setter
}

(1)请求范围

我们可以定义bean的请求范围使用@ scope注释:

@Bean
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator requestScopedBean() {
    return new HelloMessageGenerator();
}

proxyMode属性是必要的,因为目前的web应用程序上下文的实例化,没有主动请求。Spring创建一个代理作为依赖项注入,并实例化目标bean需要时在一个请求。

我们也可以使用一个@RequestScope由注释,充当一个上述定义的快捷方式:

@Bean
@RequestScope
public HelloMessageGenerator requestScopedBean() {
    return new HelloMessageGenerator();
}

接下来,我们可以定义一个控制器requestScopedBean注入引用。我们需要访问相同的请求两次来测试web具体范围。

如果我们显示消息每次请求运行时,我们可以看到,该值重置为零,即使后来改变的方法。这是因为不同的bean实例为每个请求返回。

@Controller
public class ScopesController {
    @Resource(name = "requestScopedBean")
    HelloMessageGenerator requestScopedBean;
    @RequestMapping("/scopes/request")
    public String getRequestScopeMessage(final Model model) {
        model.addAttribute("previousMessage", requestScopedBean.getMessage());
        requestScopedBean.setMessage("Good morning!");
        model.addAttribute("currentMessage", requestScopedBean.getMessage());
        return "scopesExample";
    }
}

(2)会话范围

我们可以定义的bean会话范围以类似的方式:

@Bean
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator sessionScopedBean() {
    return new HelloMessageGenerator();
}

还有一个专门的由注释我们可以用来简化bean定义:

@Bean
@SessionScope
public HelloMessageGenerator sessionScopedBean() {
    return new HelloMessageGenerator();
}

接下来,我们定义了一个控制器与sessionScopedBean参考。再一次,我们需要运行两个请求为了显示消息字段的值是相同的会话。

在这种情况下,当请求是由第一次消息为空值。然而,一旦改变,这个值保留为后续请求返回相同的bean的实例对整个会话。

@Controller
public class ScopesController {
    @Resource(name = "sessionScopedBean")
    HelloMessageGenerator sessionScopedBean;
    @RequestMapping("/scopes/session")
    public String getSessionScopeMessage(final Model model) {
        model.addAttribute("previousMessage", sessionScopedBean.getMessage());
        sessionScopedBean.setMessage("Good afternoon!");
        model.addAttribute("currentMessage", sessionScopedBean.getMessage());
        return "scopesExample";
    }
}

(3)应用范围

应用范围创建bean实例的生命周期ServletContext。

这是类似于单例的范围,但是有一个非常重要的区别对于bean的范围。

当bean是应用程序作用域,同样的bean的实例共享多个基于servlet的应用程序运行在同一ServletContext,而单范围内bean只局限于单个应用程序上下文。

让我们创建bean与应用范围:

@Bean
@Scope(
  value = WebApplicationContext.SCOPE_APPLICATION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator applicationScopedBean() {
    return new HelloMessageGenerator();
}

类似于请求和会话作用域,我们可以使用更短的版本:

@Bean
@ApplicationScope
public HelloMessageGenerator applicationScopedBean() {
    return new HelloMessageGenerator();
}

现在让我们创建一个控制器,这个bean引用:

@Controller
public class ScopesController {
    @Resource(name = "applicationScopedBean")
    HelloMessageGenerator applicationScopedBean;
    @RequestMapping("/scopes/application")
    public String getApplicationScopeMessage(final Model model) {
        model.addAttribute("previousMessage", applicationScopedBean.getMessage());
        applicationScopedBean.setMessage("Good afternoon!");
        model.addAttribute("currentMessage", applicationScopedBean.getMessage());
        return "scopesExample";
    }
}

applicationScopedBean在这种情况下,一旦设置,该值为所有后续请求消息将被保留,会话,甚至不同的servlet将访问这个bean的应用程序,它运行在相同的ServletContext。

(4)WebSocket范围

最后,让我们创建的bean websocket范围:

@Bean
@Scope(scopeName = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator websocketScopedBean() {
    return new HelloMessageGenerator();
}

当第一次访问,WebSocket范围bean存储在WebSocket会话属性。然后返回相同的bean实例时,在整个WebSocket会话bean访问。

我们也可以说,它表现出单的行为,但只局限于一个WebSocket会话。

以上就是关于“Spring作用域的快速指南”的介绍,大家如果想了解更多相关知识,不妨来关注一下本站的Java在线学习技术文档,里面的课程内容细致全面,很适合没有基础的小伙伴学习,希望对大家能够有所帮助哦。

提交申请后,顾问老师会电话与您沟通安排学习

免费课程推荐 >>
技术文档推荐 >>