当前位置: 首页 > news >正文

【Spring Boot 3】获取已注入的Bean

【Spring Boot 3】获取已注入的Bean

  • 背景
  • 介绍
  • 开发环境
  • 开发步骤及源码
  • 工程目录结构
  • 总结

背景

软件开发是一门实践性科学,对大多数人来说,学习一种新技术不是一开始就去深究其原理,而是先从做出一个可工作的DEMO入手。但在我个人学习和工作经历中,每次学习新技术总是要花费或多或少的时间、检索不止一篇资料才能得出一个可工作的DEMO,这占用了我大量的时间精力。因此本文旨在通过一篇文章即能还原出可工作的、甚至可用于生产的DEMO,期望初学者能尽快地迈过0到1的这一步骤,并在此基础上不断深化对相关知识的理解。
为达以上目的,本文会将开发环境、工程目录结构、开发步骤及源码尽量全面地展现出来,文字描述能简则简,能用代码注释的绝不在正文中再啰嗦一遍,正文仅对必要且关键的信息做重点描述。

介绍

本文介绍开发Spring Boot应用如何获取已注入的Bean实例。

开发环境

分类名称版本
操作系统WindowsWindows 11
JDKOracle JDK21.0.1
IDEIntelliJ IDEA2023.3.4
构建工具Apache Maven3.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 背景介绍开发环境开发步骤及源码工程目录结构总结 背景 软件开发是一门实践性科学&#xff0c;对大多数人来说&#xff0c;学习一种新技术不是一开始就去深究其原理&#xff0c;而是先从做出一个可工作的DEMO入手。但在我个人学习和工作经历…...

C# 对于点位置的判断

1.判断点是否在一群点内部 要判断一个点是否在一个由多个点围成的多边形内部&#xff08;例如一圈点&#xff09;&#xff0c;可以使用射线法&#xff08;Ray Casting Algorithm&#xff09;来实现。以下是一个简单的 C# 实现示例 using System;public class Point {public d…...

最新CLion + STM32 + CubeMX 开发环境搭建

网上有不少相关教程&#xff0c;但都是基于老版本Clion&#xff0c;新版有一些改变&#xff0c;但整体是简单了。 PS&#xff1a;本教程基于CLion 2023.3.4 安装所需工具参考&#xff1a;Clion搭建stm32开发环境&#xff08;STM32F103C8T6&#xff09;&#xff0c;有这一篇就够…...

【Python3】观察者模式

观察者模式&#xff08;Observer Pattern&#xff09;是一种常见的设计模式&#xff0c;用于定义对象之间的一对多依赖关系&#xff0c;使得一个对象的状态改变能够通知所有依赖于它的对象并自动更新。 在观察者模式中&#xff0c;有两个核心角色&#xff1a; Subject&#xf…...

HTML5 Web Worker之性能优化

描述 由于 JavaScript 是单线程的&#xff0c;当执行比较耗时的任务时&#xff0c;就会阻塞主线程并导致页面无法响应&#xff0c;这就是 Web Workers 发挥作用的地方。它允许在一个单独的线程&#xff08;称为工作线程&#xff09;中执行耗时的任务。这使得 JavaScript 代码可…...

应对恶意IP攻击的有效方法

在当今数字化时代&#xff0c;网络攻击已经成为了互联网安全的重大挑战之一。恶意IP攻击是网络安全领域中的一种常见威胁&#xff0c;它可能导致数据泄露、服务中断、系统瘫痪等严重后果。因此&#xff0c;有效地应对恶意IP攻击至关重要。IP数据云将深入探讨如何应对恶意IP攻击…...

如何使用“Docker registry创建本地仓库,在服务器之间进行文件push和pull”?

1.1、在服务器1&#xff0c;运行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 文件&#xff0c; 192.168.xxx.xxx 换成你自己 registry 服务的地址 sudo na…...

Rocky Linux - Primavera P6 EPPM 安装及分享

引言 继上一期发布的Redhat Linux版环境发布之后&#xff0c;近日我又制作了基于Rocky Enterprise Linux 的P6虚拟机环境&#xff0c;同样里面包含了全套P6 最新版应用服务 此虚拟机仅用于演示、培训和测试目的。如您在生产环境中使用此虚拟机&#xff0c;请先与Oracle Primav…...

API 管理调研

当前大部分团队内 API 管理都是依赖 Postman&#xff0c;postman最大的问题是共享问题&#xff0c;如果我要使用另外一个人已经调试好的 API 非常麻烦。因此&#xff0c;能实现协作的 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程序时用于存储数据和状态信息的内存区域。它分为多个部分&#xff0c;每个部分都有其特定的作用和存放的内容。 1. 方法区&#xff08;Method Area&#xff09; 作用&#xff1a;方法区是所有线程共享的内存区域&#xff0c;用于存放已被虚…...

数据体系规范化

基础是标准化、规范化 建立数据仓库,面向主题的、集成的、相对稳定的、反映历史变化的数据集合,以支持管理决策decision making 大数据:大量volumn、多样variety、快速velocity、价值密度低value、准确性veracity、可视化visualization、合法性validity 多源数据、多样数…...

从政府工作报告探计算机行业发展

从政府工作报告中&#xff0c;我们可以深入洞察计算机行业在未来一年的发展趋势和政策导向。报告中明确提出了数字经济创新发展的重要性&#xff0c;以及制造业数字化转型、服务业数字化、智慧城市和数字乡村建设等关键任务&#xff0c;这些都为计算机行业提供了广阔的发展空间…...

【软件工具】网络性能测试工具 Iperf

Iperf 是一款专业的开源网络性能测试工具&#xff0c;它被广泛用于测量网络带宽、延迟、抖动和数据包丢失等网络性能指标&#xff0c;支持 TCP 和 UDP 等&#xff0c;可用于点对点或客户端-服务器等模式的网络测试。 软件获取 官方下载地址&#xff1a;https://iperf.fr/iper…...

Day32:安全开发-JavaEE应用Servlet路由技术JDBCMybatis数据库生命周期

目录 JavaEE-HTTP-Servlet&路由&周期 JavaEE-数据库-JDBC&Mybatis&库 思维导图 Java知识点&#xff1a; 功能&#xff1a;数据库操作&#xff0c;文件操作&#xff0c;序列化数据&#xff0c;身份验证&#xff0c;框架开发&#xff0c;第三方库使用等. 框架…...

C语言下使用SQL语言

需头文件&#xff1a;#include<sqlite.h>---需下载 1.sqlite3_open int sqlite3_open( const char *filename, /* Database filename (UTF-8) */ sqlite3 **ppDb /* OUT: SQLite db handle */ ); 功能: 打开数据库文件(…...

Gitea相关漏洞

Go代码审计&#xff1a;Gitea远程命令执行漏洞链_新闻中心-网盾网络安全培训学校 Vulhub靶场gitea-1.4远程代码执行漏洞复现_gitea 漏洞-CSDN博客...

基于深度学习的图像去雨去雾

基于深度学习的图像去雨去雾 文末附有源码下载地址 b站视频地址&#xff1a; https://www.bilibili.com/video/BV1Jr421p7cT/ 基于深度学习的图像去雨去雾&#xff0c;使用的网络为unet&#xff0c; 网络代码&#xff1a; import torch import torch.nn as nn from torchsumm…...

使用JS的for循环实现九九乘法表

九九乘法表是我们在学习基础数学时经常会遇到的一个概念。在编程中&#xff0c;使用循环结构来实现九九乘法表是一个很好的练习。下面&#xff0c;我将详细介绍如何使用JavaScript的for循环来实现九九乘法表。 首先&#xff0c;我们需要理解for循环的基本结构。在JavaScript中…...

Leetcode 70 爬楼梯

文章目录 1. 题目描述2. 我的尝试 1. 题目描述 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 示例 1&#xff1a; 输入&#xff1a;n 2 输出&#xff1a;2 解释&#xff1a;有两种方法可以爬到…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15

缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下&#xff1a; struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

家政维修平台实战20:权限设计

目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系&#xff0c;主要是分成几个表&#xff0c;用户表我们是记录用户的基础信息&#xff0c;包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题&#xff0c;不同的角色&#xf…...

linux 错误码总结

1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

【2025年】解决Burpsuite抓不到https包的问题

环境&#xff1a;windows11 burpsuite:2025.5 在抓取https网站时&#xff0c;burpsuite抓取不到https数据包&#xff0c;只显示&#xff1a; 解决该问题只需如下三个步骤&#xff1a; 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...