Spring Bean 范围

2023-11-15

Spring Bean Scopes 允许我们更精细地控制 bean 实例的创建。有时我们希望将 bean 实例创建为单例,但在其他一些情况下,我们可能希望在每次请求时或在会话中创建一次。

Spring Bean 范围

有五种类型春豆 scopes:

  1. 单例- 只会为 spring 容器创建一个 spring bean 实例。这是默认的 spring bean 范围。使用此作用域时,请确保 bean 没有共享实例变量,否则可能会导致数据不一致问题。
  2. 原型– 每次从 spring 容器请求 bean 时,都会创建一个新实例。
  3. request– 这与原型范围相同,但它旨在用于 Web 应用程序。将为每个 HTTP 请求创建一个新的 bean 实例。
  4. session– 容器将为每个 HTTP 会话创建一个新的 bean。
  5. 全球会议– 这用于为 Portlet 应用程序创建全局会话 Bean。

Spring Bean 单例和原型范围

Spring bean 单例和原型范围可以在独立的 spring 应用程序中使用。让我们看看如何使用轻松配置这些范围@Scope注解。假设我们有一个 java bean 类。

package com.journaldev.spring;

public class MyBean {

	public MyBean() {
		System.out.println("MyBean instance created");
	}

}

让我们定义弹簧配置类,我们将在其中定义从 spring 容器获取 MyBean 实例的方法。

package com.journaldev.spring;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

@Configuration
public class MyConfiguration {
	
	@Bean
	@Scope(value="singleton")
    public MyBean myBean() {
		return new MyBean();
	}
	
}

注意singleton是默认范围,所以我们可以删除@Scope(value="singleton")从上面的bean定义。现在让我们创建一个 main 方法并测试单例范围。

package com.journaldev.spring;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MySpringApp {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
		ctx.register(MyConfiguration.class);
		ctx.refresh();

		 MyBean mb1 = ctx.getBean(MyBean.class);
		 System.out.println(mb1.hashCode());

		 MyBean mb2 = ctx.getBean(MyBean.class);
		 System.out.println(mb2.hashCode());

		ctx.close();
	}

}

当执行上面的程序时,我们将得到如下输出。

MyBean instance created
867988177
867988177

请注意,两个 MyBean 实例具有相同的哈希码,并且构造函数被调用一次,这意味着 spring 容器始终返回相同的 MyBean 实例。现在我们将范围更改为prototype.

@Bean
@Scope(value="prototype")
public MyBean myBean() {
	return new MyBean();
}

这次执行 main 方法时我们将得到以下输出。

MyBean instance created
867988177
MyBean instance created
443934570

很明显,每次从 Spring 容器请求时都会创建 MyBean 实例。现在我们将范围更改为request.

@Bean
@Scope(value="request")
public MyBean myBean() {
	return new MyBean();
}

在这种情况下,我们将得到以下异常。

Exception in thread "main" java.lang.IllegalStateException: No Scope registered for scope name 'request'
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:347)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:224)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1015)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:339)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:334)
	at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1107)
	at com.journaldev.spring.MySpringApp.main(MySpringApp.java:12)

这是因为request, session and global-session范围不适用于独立应用程序。

Spring Bean 请求和会话范围

For spring bean request and session scope example, we will create Spring Boot web application. Create a spring boot starter project and choose “web” so that we can run it as a web application. spring boot starter project Our final project will look like below image. spring bean scopes spring boot web app project ServletInitializer and SpringBootMvcApplication are auto generated spring boot classes. We don’t need to make any changes there. Here is my pom.xml file, have a look at the dependencies for our application. Your pom.xml file might be slightly different based on the Eclipse version you are using.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.journaldev.spring</groupId>
	<artifactId>Spring-Boot-MVC</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>

	<name>Spring-Boot-MVC</name>
	<description>Spring Beans Scope MVC</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>10</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>


</project>

让我们创建一些 spring 组件,并将它们配置为 spring 容器中的 spring bean,范围为request and session.

Spring Bean 请求范围

package com.journaldev.spring;

import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;

@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class DataRequestScope {

	private String name = "Request Scope";
	
	public DataRequestScope() {
		System.out.println("DataRequestScope Constructor Called");
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

Spring Bean 会话范围

package com.journaldev.spring;

import org.springframework.context.annotation.Scope;
import java.time.LocalDateTime;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;

@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class DataSessionScope {

	private String name = "Session Scope";
	
	public DataSessionScope() {
		System.out.println("DataSessionScope Constructor Called at "+LocalDateTime.now());
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

弹簧组件

现在让我们创建一个 spring 组件并使用 spring 自动配置上面的 beans。

package com.journaldev.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Customer {

	@Autowired
	private DataRequestScope dataRequestScope;
	
	@Autowired
	private DataSessionScope dataSessionScope;

	public DataRequestScope getDataRequestScope() {
		return dataRequestScope;
	}

	public void setDataRequestScope(DataRequestScope dataRequestScope) {
		this.dataRequestScope = dataRequestScope;
	}

	public DataSessionScope getDataSessionScope() {
		return dataSessionScope;
	}

	public void setDataSessionScope(DataSessionScope dataSessionScope) {
		this.dataSessionScope = dataSessionScope;
	}


}

弹簧支架控制器

最后,让我们创建一个 RestController 类并配置一些 API 端点以用于测试目的。

package com.journaldev.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloData {

	@Autowired
	private Customer customer;
	
	@RequestMapping("/nameRS")
	public String helloRS() {
		return customer.getDataRequestScope().getName();
	}
	
	@RequestMapping("/nameSSUpdated")
	public String helloSSUpdated() {
		customer.getDataSessionScope().setName("Session Scope Updated");
		return customer.getDataSessionScope().getName();
	}
	
	@RequestMapping("/nameSS")
	public String helloSS() {
		return customer.getDataSessionScope().getName();
	}
}

Spring Boot 会话超时配置

最后我们必须配置 Spring Boot 会话超时变量,添加以下属性src/main/resources/application.properties.

server.session.cookie.max-age= 1
server.session.timeout= 1

现在我们的具有会话范围的 Spring beans 将在一分钟内失效。只需运行SpringBootMvcApplication类作为 Spring Boot 应用程序。您应该看到下面我们配置的端点的输出。

2018-05-23 17:02:25.830  INFO 6921 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/nameRS]}" onto public java.lang.String com.journaldev.spring.HelloData.helloRS()
2018-05-23 17:02:25.831  INFO 6921 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/nameSSUpdated]}" onto public java.lang.String com.journaldev.spring.HelloData.helloSSUpdated()
2018-05-23 17:02:25.832  INFO 6921 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/nameSS]}" onto public java.lang.String com.journaldev.spring.HelloData.helloSS()

Spring Bean 请求范围测试

打开任何浏览器并转到 URLhttps://localhost:8080/nameRS并检查控制台输出。你应该看到DataRequestScope Constructor Called根据每个请求打印。

Spring Bean 会话范围测试

Go to https://localhost:8080/nameSS and you would get following output. Spring Bean Session Scope Test Output Now go to https://localhost:8080/nameSSUpdated so that DataSessionScope name value is updated to Session Scope Updated. Spring Bean Scopes test Now again go to https://localhost:8080/nameSS and you should see the updated value. spring beans scope By this time, you should see DataSessionScope Constructor Called at XXX only once in the console output. Now wait for 1 minute so that our session scoped bean is invalidated. Then again go to https://localhost:8080/nameSS and you should see the original output. Also you should check console message for creation of DataSessionScope again by the container. spring bean session scope That’s all for spring beans scope tutorial.

您可以从我们的网站下载 Spring Beans Scope Spring Boot 项目GitHub 存储库.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring Bean 范围 的相关文章

随机推荐

  • 如何在 Ubuntu 16.04 上安装 MySQL

    介绍 MySQL是一个开源数据库管理系统 通常作为流行的一部分安装LAMP Linux Apache MySQL PHP Python Perl 堆栈 它使用关系数据库和 SQL 结构化查询语言 来管理其数据 简短版本的安装很简单 更新您的
  • Java IO 教程

    Java提供了几个类java io用于处理文本 流数据和文件系统的包 我最近提供了几个有关 Java 文件和 Java IO 的示例 这篇文章是所有 Java IO 文章的索引 Java IO 如何在 Java 中创建新文件在这篇文章中 您
  • Java Stream Collect() 方法示例

    Java Streamcollect 对流的元素执行可变归约操作 这是终端操作 什么是可变约简操作 可变归约操作处理流元素 然后将其累积到可变结果容器中 处理元素后 组合函数将合并所有结果容器以创建结果 Java Stream Collec
  • 快速初始化()

    在本 Swift 教程中 我们将讨论一个重要的概念 即 Swift init 或 Swift 初始化 初始化是当我们创建某种类型的实例时发生的事情 快速初始化 初始化是准备类 结构或枚举的实例以供使用的过程 此过程涉及为该实例上的每个存储属
  • 如何在 Debian Wheezy 上使用 Postfix 安装和配置 DKIM

    介绍 对于大多数邮件服务器管理员来说 被错误地标记为垃圾邮件发送者所带来的挫败感并不奇怪 通过排除服务器受损的可能性 错误标记通常是由以下原因之一引起的 该服务器是一个开放的邮件中继 发件人或服务器的 IP 地址已列入黑名单 服务器没有完全
  • Linux/Unix 中的 AWK 命令

    AWK 适用于模式搜索和处理 该脚本运行以搜索一个或多个文件以识别匹配模式以及所述模式是否执行特定任务 在本指南中 我们将了解 AWK Linux 命令并了解它的功能 AWK 可以执行哪些操作 逐行扫描文件 将每个输入行拆分为字段 将输入行
  • 如何在 Python 中将字符串转换为日期时间或时间对象

    介绍 蟒蛇datetime and time模块均包括strptime 将字符串转换为对象的类方法 在本文中 您将使用strptime 将字符串转换为datetime and struct time 对象 将字符串转换为datetime对象
  • 如何在 Ubuntu 18.04 上使用 Python 3 设置 Jupyter Notebook

    介绍 Jupyter笔记本是一个开源 Web 应用程序 可让您创建和共享交互式代码 可视化等 该工具可与多种编程语言一起使用 包括 Python Julia R Haskell 和 Ruby 它通常用于处理数据 统计建模和机器学习 本教程将
  • 了解 Vue.js 生命周期挂钩

    介绍 生命周期挂钩是了解您正在使用的库如何在幕后工作的窗口 生命周期钩子允许您知道组件何时被创建 添加到 DOM 更新或销毁 本文将向您介绍 Vue js 中的创建 安装 更新和销毁钩子 先决条件 要完成本教程 您需要 熟悉 Vue js
  • Java 单例类中的线程安全

    Singleton 是最广泛使用的创建型设计模式之一 用于限制应用程序创建的对象 如果是在多线程环境中使用 那么单例类的线程安全性就非常重要 在现实应用程序中 数据库连接或企业信息系统 EIS 等资源是有限的 应明智地使用以避免任何资源紧缩
  • Fail2Ban 如何保护 Linux 服务器上的服务

    介绍 SSH 是连接云服务器的事实上的方法 它耐用且可扩展 随着新的加密标准的开发 它们可用于生成新的 SSH 密钥 确保核心协议保持安全 然而 没有任何协议或软件堆栈是完全万无一失的 SSH 在互联网上如此广泛的部署意味着它代表了一种非常
  • 如何在运行 Ubuntu 的 VPS 上安装和使用 Composer

    Status 已弃用 本文介绍不再受支持的 Ubuntu 版本 如果您当前运行的服务器运行 Ubuntu 12 04 我们强烈建议您升级或迁移到受支持的 Ubuntu 版本 升级到Ubuntu 14 04 从 Ubuntu 14 04 升级
  • 如何在 Rocky Linux 9 上安装 Node.js

    介绍 Node js是用于服务器端编程的 JavaScript 运行时 它允许开发人员使用 JavaScript 创建可扩展的后端功能 这是许多人在基于浏览器的 Web 开发中已经熟悉的语言 在本指南中 您将了解在 Rocky Linux
  • Java 堆空间与堆栈 - Java 中的内存分配

    不久前我写了几篇关于Java 垃圾收集 and Java 是按值传递 之后我收到了很多电子邮件来解释Java堆空间 Java堆栈内存 Java中的内存分配它们之间有什么区别 您会在 Java Java EE 书籍和教程中看到很多对堆和堆栈内
  • Spring WebFlux - Spring 响应式编程

    Spring WebFlux是Spring 5中引入的新模块 Spring WebFlux是Spring框架中向反应式编程模型迈出的第一步 Spring 响应式编程 如果您是反应式编程模型的新手 那么我强烈建议您阅读以下文章来了解反应式编程
  • 如何在 Ubuntu 16.04 上设置 Apache 虚拟主机

    介绍 Apache Web 服务器是在互联网上提供 Web 内容的最流行的方式 它占互联网上所有活跃网站的一半以上 并且非常强大和灵活 Apache 将其功能和组件分解为可以独立定制和配置的单独单元 描述单个站点或域的基本单位称为virtu
  • Android 倒计时器示例

    在这个 android 倒数计时器示例中 我们将实现一个计时器对象来显示进度进度条 我们将在本教程中构建的应用程序是测验应用程序中的一个有用组件 其中以图形方式显示完成该级别的剩余时间 以增强用户体验 Android 倒计时器 Androi
  • 如何在 Ubuntu 18.04 上设置私有 Docker 注册表

    作者选择了阿帕奇软件基金会接受捐赠作为为捐款而写程序 介绍 Docker 注册表是一个管理存储和交付 Docker 容器镜像的应用程序 注册表集中容器映像并减少开发人员的构建时间 Docker 镜像通过虚拟化保证相同的运行时环境 但构建镜像
  • C 编程中的 fgets() 和 gets()

    介绍 我们都熟悉scanf 功能 它是适用于获取基本用户输入的主要功能 虽然scanf 在接受诸如以下输入时效果很好整数 字符 浮点数等等 在获取包含空格的字符串输入时 它肯定会落后 让我们看一个例子 include
  • Spring Bean 范围

    Spring Bean Scopes 允许我们更精细地控制 bean 实例的创建 有时我们希望将 bean 实例创建为单例 但在其他一些情况下 我们可能希望在每次请求时或在会话中创建一次 Spring Bean 范围 有五种类型春豆 sco