【Spring Boot 3】获取已注入的Bean
【Spring Boot 3】获取已注入的Bean
- 背景
- 介绍
- 开发环境
- 开发步骤及源码
- 工程目录结构
- 总结
背景
软件开发是一门实践性科学,对大多数人来说,学习一种新技术不是一开始就去深究其原理,而是先从做出一个可工作的DEMO入手。但在我个人学习和工作经历中,每次学习新技术总是要花费或多或少的时间、检索不止一篇资料才能得出一个可工作的DEMO,这占用了我大量的时间精力。因此本文旨在通过一篇文章即能还原出可工作的、甚至可用于生产的DEMO,期望初学者能尽快地迈过0到1的这一步骤,并在此基础上不断深化对相关知识的理解。
为达以上目的,本文会将开发环境、工程目录结构、开发步骤及源码尽量全面地展现出来,文字描述能简则简,能用代码注释的绝不在正文中再啰嗦一遍,正文仅对必要且关键的信息做重点描述。
介绍
本文介绍开发Spring Boot应用如何获取已注入的Bean实例。
开发环境
| 分类 | 名称 | 版本 |
|---|---|---|
| 操作系统 | Windows | Windows 11 |
| JDK | Oracle JDK | 21.0.1 |
| IDE | IntelliJ IDEA | 2023.3.4 |
| 构建工具 | Apache Maven | 3.9.6 |
开发步骤及源码
1> 创建Maven工程,添加依赖。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.jiyongliang</groupId><artifactId>springboot3-bean</artifactId><version>0.0.1</version></parent><artifactId>springboot3-bean-obtain</artifactId><properties><java.version>21</java.version><maven.compiler.source>21</maven.compiler.source><maven.compiler.target>21</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><spring-boot.version>3.2.2</spring-boot.version><lombok.version>1.18.30</lombok.version></properties><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version></dependency></dependencies><build><pluginManagement><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version></plugin></plugins></pluginManagement><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>
2> 定义SpringBoot应用启动类。
package org.example.springboot;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class SpringBoot3BeanObtainApplication {public static void main(String[] args) {SpringApplication.run(SpringBoot3BeanObtainApplication.class, args);}
}
3> 定义获取已注入Bean的核心类。
package org.example.springboot.manager;import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;@Component
@Getter
@Slf4j
public class BeanManager {private final ApplicationContext applicationContext;public BeanManager(ApplicationContext applicationContext) {this.applicationContext = applicationContext;}/*** 通过Bean名称获取*/public Object getBean(String name) {try {return this.applicationContext.getBean(name);} catch (NoSuchBeanDefinitionException e) {log.error(e.getMessage());return null;}}/*** 通过Bean类型获取* 如果存在同一类型的多个Bean实例则会抛出NoSuchBeanDefinitionException,异常信息:expected single matching bean but found 2*/public <T> T getBean(Class<T> clazz) {try {return this.applicationContext.getBean(clazz);} catch (NoSuchBeanDefinitionException e) {log.error(e.getMessage());return null;}}/*** 通过Bean名称和类型获取*/public <T> T getBean(String name, Class<T> clazz) {try {return this.applicationContext.getBean(name, clazz);} catch (NoSuchBeanDefinitionException e) {log.error(e.getMessage());return null;}}
}
4> 定义测试Bean。
package org.example.springboot.bean;import lombok.AllArgsConstructor;
import lombok.Data;@AllArgsConstructor
@Data
public class CustomBean {private Integer id;private String name;
}
5> 配置注入Bean。
package org.example.springboot.config;import org.example.springboot.bean.CustomBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class CustomBeanConfig {@Bean("beanX")public CustomBean beanX() {return new CustomBean(1, "Bean-X");}@Bean("beanY")public CustomBean beanY() {return new CustomBean(2, "Bean-X");}
}
6> 创建单元测试。
package org.example.springboot.manager;import jakarta.annotation.Resource;
import org.assertj.core.api.Assertions;
import org.example.springboot.bean.CustomBean;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
class BeanManagerTests {@AutowiredBeanManager beanManager;@Resource(name = "beanX")CustomBean beanX;@Resource(name = "beanY")CustomBean beanY;@Testvoid test() {System.out.println("Test get bean by name");Assertions.assertThat(beanManager.getBean("beanX")).isSameAs(beanX);Assertions.assertThat(beanManager.getBean("beanY")).isSameAs(beanY);System.out.println("Test get bean by type");Assertions.assertThat(beanManager.getBean(CustomBean.class)).isNull();System.out.println("Test get bean by name and type");Assertions.assertThat(beanManager.getBean("beanX", CustomBean.class)).isSameAs(beanX);Assertions.assertThat(beanManager.getBean("beanY", CustomBean.class)).isSameAs(beanY);}
}
7> 单元测试结果。

单元测试日志:
Test get bean by name
Test get bean by type
2024-03-08T20:31:34.845+08:00 ERROR 18872 --- [ main] o.e.springboot.manager.BeanManager : No qualifying bean of type 'org.example.springboot.bean.CustomBean' available: expected single matching bean but found 2: beanX,beanY
Test get bean by name and type
从日志中可以看出,测试根据类型获取注入的Bean时抛出了异常,因为找到2个同样类型的Bean,无法判断应该返回哪个Bean,因此通过类型获取Bean时,有且仅有一个类型匹配的Bean才会正常返回。
工程目录结构

总结
测试用的Bean和配置注入放在 src/test 目录下是为了辅助测试。
相关文章:
【Spring Boot 3】获取已注入的Bean
【Spring Boot 3】获取已注入的Bean 背景介绍开发环境开发步骤及源码工程目录结构总结 背景 软件开发是一门实践性科学,对大多数人来说,学习一种新技术不是一开始就去深究其原理,而是先从做出一个可工作的DEMO入手。但在我个人学习和工作经历…...
C# 对于点位置的判断
1.判断点是否在一群点内部 要判断一个点是否在一个由多个点围成的多边形内部(例如一圈点),可以使用射线法(Ray Casting Algorithm)来实现。以下是一个简单的 C# 实现示例 using System;public class Point {public d…...
最新CLion + STM32 + CubeMX 开发环境搭建
网上有不少相关教程,但都是基于老版本Clion,新版有一些改变,但整体是简单了。 PS:本教程基于CLion 2023.3.4 安装所需工具参考:Clion搭建stm32开发环境(STM32F103C8T6),有这一篇就够…...
【Python3】观察者模式
观察者模式(Observer Pattern)是一种常见的设计模式,用于定义对象之间的一对多依赖关系,使得一个对象的状态改变能够通知所有依赖于它的对象并自动更新。 在观察者模式中,有两个核心角色: Subject…...
HTML5 Web Worker之性能优化
描述 由于 JavaScript 是单线程的,当执行比较耗时的任务时,就会阻塞主线程并导致页面无法响应,这就是 Web Workers 发挥作用的地方。它允许在一个单独的线程(称为工作线程)中执行耗时的任务。这使得 JavaScript 代码可…...
应对恶意IP攻击的有效方法
在当今数字化时代,网络攻击已经成为了互联网安全的重大挑战之一。恶意IP攻击是网络安全领域中的一种常见威胁,它可能导致数据泄露、服务中断、系统瘫痪等严重后果。因此,有效地应对恶意IP攻击至关重要。IP数据云将深入探讨如何应对恶意IP攻击…...
如何使用“Docker registry创建本地仓库,在服务器之间进行文件push和pull”?
1.1、在服务器1,运行registry docker run -d -p 5000:5000 -v ${PWD}/registry:/var/lib/registry --restart always --name registry registry:2.7.11.2、编辑/etc/docker/daemon.json 文件, 192.168.xxx.xxx 换成你自己 registry 服务的地址 sudo na…...
Rocky Linux - Primavera P6 EPPM 安装及分享
引言 继上一期发布的Redhat Linux版环境发布之后,近日我又制作了基于Rocky Enterprise Linux 的P6虚拟机环境,同样里面包含了全套P6 最新版应用服务 此虚拟机仅用于演示、培训和测试目的。如您在生产环境中使用此虚拟机,请先与Oracle Primav…...
API 管理调研
当前大部分团队内 API 管理都是依赖 Postman,postman最大的问题是共享问题,如果我要使用另外一个人已经调试好的 API 非常麻烦。因此,能实现协作的 API 管理将极大提升效率。 Yapi https://github.com/YMFE/yapi https://hellosean1025.gi…...
在centOS服务器安装docker,并使用docker配置nacos
遇到安装慢的情况可以优先选择阿里镜像 安装docker 更新yum版本 yum update安装所需软件包 yum install -y yum-utils device-mapper-persistent-data lvm2添加Docker仓库 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.rep…...
JVM运行时数据区概述以及分别存放的内容
JVM的运行时数据区是JVM在执行Java程序时用于存储数据和状态信息的内存区域。它分为多个部分,每个部分都有其特定的作用和存放的内容。 1. 方法区(Method Area) 作用:方法区是所有线程共享的内存区域,用于存放已被虚…...
数据体系规范化
基础是标准化、规范化 建立数据仓库,面向主题的、集成的、相对稳定的、反映历史变化的数据集合,以支持管理决策decision making 大数据:大量volumn、多样variety、快速velocity、价值密度低value、准确性veracity、可视化visualization、合法性validity 多源数据、多样数…...
从政府工作报告探计算机行业发展
从政府工作报告中,我们可以深入洞察计算机行业在未来一年的发展趋势和政策导向。报告中明确提出了数字经济创新发展的重要性,以及制造业数字化转型、服务业数字化、智慧城市和数字乡村建设等关键任务,这些都为计算机行业提供了广阔的发展空间…...
【软件工具】网络性能测试工具 Iperf
Iperf 是一款专业的开源网络性能测试工具,它被广泛用于测量网络带宽、延迟、抖动和数据包丢失等网络性能指标,支持 TCP 和 UDP 等,可用于点对点或客户端-服务器等模式的网络测试。 软件获取 官方下载地址:https://iperf.fr/iper…...
Day32:安全开发-JavaEE应用Servlet路由技术JDBCMybatis数据库生命周期
目录 JavaEE-HTTP-Servlet&路由&周期 JavaEE-数据库-JDBC&Mybatis&库 思维导图 Java知识点: 功能:数据库操作,文件操作,序列化数据,身份验证,框架开发,第三方库使用等. 框架…...
C语言下使用SQL语言
需头文件:#include<sqlite.h>---需下载 1.sqlite3_open int sqlite3_open( const char *filename, /* Database filename (UTF-8) */ sqlite3 **ppDb /* OUT: SQLite db handle */ ); 功能: 打开数据库文件(…...
Gitea相关漏洞
Go代码审计:Gitea远程命令执行漏洞链_新闻中心-网盾网络安全培训学校 Vulhub靶场gitea-1.4远程代码执行漏洞复现_gitea 漏洞-CSDN博客...
基于深度学习的图像去雨去雾
基于深度学习的图像去雨去雾 文末附有源码下载地址 b站视频地址: https://www.bilibili.com/video/BV1Jr421p7cT/ 基于深度学习的图像去雨去雾,使用的网络为unet, 网络代码: import torch import torch.nn as nn from torchsumm…...
使用JS的for循环实现九九乘法表
九九乘法表是我们在学习基础数学时经常会遇到的一个概念。在编程中,使用循环结构来实现九九乘法表是一个很好的练习。下面,我将详细介绍如何使用JavaScript的for循环来实现九九乘法表。 首先,我们需要理解for循环的基本结构。在JavaScript中…...
Leetcode 70 爬楼梯
文章目录 1. 题目描述2. 我的尝试 1. 题目描述 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 示例 1: 输入:n 2 输出:2 解释:有两种方法可以爬到…...
多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...
关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
