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

[SpringBoot]如何在一个普通类中获取一个Bean

最近在项目中出现了一个这种情况:我一顿操作猛如虎的写了好几个设计模式,然后在设计模式中的类中想将数据插入数据库,因此调用Mapper持久层,但是数据怎么都写不进去,在我一顿操作猛如虎的查找下,发现在普通类中用@Autowired注入的Bean是Null,也就是说注入失败了,瞎搞。

针对以上情况,我做了三种解决方案,经测试均可行,解决方案如下:

  1. 在设计模式中只操作数据,最后还是将数据返回给Controller层,再由Controller向下调用写入数据库
  2. 简化设计模式,然后将其注册为Service,然后再Service中调用Mapper层
  3. 通过Bean工具的方式,在普通类中获取Bean,然后将内容写入数据库。

经过测试,三种情况均可行,最终我选择了"3"。

文章目录

  • 情况复现
  • 正文 | 获取一个Bean
    • 方式 1 | 通过实现`ApplicationContextAwre`方式获取Bean
      • 1.1 实现
      • 1.2 使用
    • 方式 2
      • 2.2 使用
    • 方式 3 | 继承`ApplicationObjectSupport`的方式获取Bean
      • 3.1 实现
      • 3.2 测试
    • 方式 4 | 继承`WebApplicationObjectSupport`
      • 4.2 测试
    • 方式 5 | 通过`WebApplicationContextUtils`
      • 5.1 实现
      • 5.2 测试
  • 致谢

- 以下代码均经过我的测试,请放心使用 -


情况复现

抄作业可以跳转至正文

情况复现比较简单,我们只需要一个Bean即可,Bean代码如下:

  1. Bean代码
@Component
public class TestComponent {public String say() {System.out.println("执行成功");return "执行成功";}}

在以上代码中,我们将TestComponent注册成为了一个Bean,为了严禁,我们还需要在Controller中调用一下这个类的方法测试一下该类是否真的被注入进去了,但是为了文章不要太冗余,这一块内容我省略掉,结论是:我测试过,是可以在Controller中调用的。

  1. 通过普通类调用该Bean

实现思想:我们写一个普通的类,在Controller中new出该类的对象,然后在该普通类中@Autowired的方式注入该类并调用

验证方式:首先,我们会输出该Bean的地址,如果注入成功的话,我们会得到一长串字符,其次,如果成功的话页面与控制台均有输出

  1. Controller层

    只写个方法了,类信息略

@GetMapping("/com")
public String common() {CommonClazz clazz = new CommonClazz();return clazz.say();
}
  1. 普通类CommonClazz
public class CommonClazz {@Autowiredprivate TestComponent component;public String say() {System.out.println("-----Bean:"+component);return component.say();}}

以上代码中,我们在Controller层new出来了CommonClazz的对象,在CommonClazz中我们Autowired了测试Bean,随后返回+输出,一气呵成,逻辑严谨,看似毫无问题,一执行满是BUG,执行结果如下:

页面:错误信息,找不到该页面(其实是有该路径,只不过后台报错了)

后台:报错,内容如下

在这里插入图片描述

可以看到,首先我们对Bean的地址输出是null,说明我们注入失败,什么都没拿到,因此用null来执行方法会报错也就可以理解了。

思考一下,如果我这时候new一个Service层的实现类对象,然后调用Mapper,是否可以将数据写入数据库呢?答案是否定的,因为对于new出来的Service实现类来说,它也是一个普通类,而不是Bean,但是Mapper层却是一个Bean,这样又会出现现在的问题。




正文 | 获取一个Bean

方式 1 | 通过实现ApplicationContextAwre方式获取Bean

!!强烈推荐!!

这是一种比较推荐的写法,我们不用再改写SpringBoot启动类,且获取Bean的时候也不用传入Bean的名称,只需要传入一个.class就可以了。


1.1 实现

SpringContextUtil代码如下:

@Component
public class SpringContextUtil implements ApplicationContextAware {private static ApplicationContext ac;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {ac = applicationContext;}public static <T> T getBean(Class<T> clazz) {T bean = ac.getBean(clazz);return bean;}}

正如简介中所说,这种方法不需要修改启动类,我们只需要做这些就可以正常使用了。


1.2 使用

与方式一相比ControllerCommonClass类并没有发生太大的变化,但是为了更好的阅读性,我们还是全都展示出来。

  1. Controller类(依旧省略类信息,只写方法)
@GetMapping("/com")
public void common() {CommonClazz clazz = new CommonClazz();clazz.say();
}
  1. CommonClazz
public class CommonClazz {public void say() {TestComponent bean = SpringContextUtil.getBean(TestComponent.class);System.out.println("-----Bean:"+bean);bean.say();}}
  1. Bean类省略,可以去前面复制

浏览器访问Controller层地址,信息正常输出,内容如下

在这里插入图片描述

可以看到Bean的地址被正确输出(说明不是null),也输出了Bean中方法的内容,说明Bean被正常注入了。



方式 2

!推荐!

这种实现可以在任意类中获取一个Bean,但是要修改SpringBoot启动类,并且在获取Bean的时候要传入两个参数,有点冗余,个人觉得使用起来不如方式1(当然也可以通过改写getBean()方法的方式只传入一个Bean)。


### 2.1 实现
  1. 首先我们要简单改造一下SpringBoot启动类,变动如下:
@SpringBootApplication
public class JimTestApplication {public static void main(String[] args) {ConfigurableApplicationContext run = SpringApplication.run(JimTestApplication.class, args);SpringContextUtil.setAc(run);}}
  1. 其次,我们创建一个SpringContextUtil工具类,内容如下:
public class SpringContextUtil {private static ApplicationContext ac;public static <T>  T getBean(String beanName, Class<T> clazz) {T bean = ac.getBean(beanName, clazz);return bean;}public static void setAc(ApplicationContext applicationContext){ac = applicationContext;}
}

**大功告成!**接下来只需要在普通类中调用该工具类中的方法,就可以获得一个Bean了,接下来我们测试一下、

测试思路:与上面一样,我们通过Controller new普通类对象,然后在普通类对象中通过这个工具类获取一个Bean,并且输出Bean的地址以及调用Bean的方法

为了方便测试,所有的方法都不加返回值了,直接输出 ,后面也是如此。


2.2 使用

  1. Controller类new CommonClazz()(依旧省略类信息,直接写方法)
@GetMapping("/com")
public void common() {CommonClazz clazz = new CommonClazz();clazz.say();
}
  1. CommonClazz类信息如下
public class CommonClazz {public void say() {// 使用如下TestComponent bean = SpringContextUtil.getBean("testComponent",TestComponent.class);System.out.println("-----Bean:"+bean);bean.say();}}
  1. Bean(TestComponent)没有做多大的改动,只是有返回值改成void了,为了节省篇幅,这里也省略不写了。

我们在浏览器调用Controller的地址之后,控制台得到如下输出:

在这里插入图片描述

结论:Bean被正确注入



方式 3 | 继承ApplicationObjectSupport的方式获取Bean

!!不推荐!!

这是一种比较鸡肋的方法,使用起来有很大的局限性:它只能在Bean中使用。因为它本身也需要作为Bean被注入后才能生效。


3.1 实现

  1. SpringContextUtil类内容如下
@Service
public class SpringContextUtil extends ApplicationObjectSupport {public <T> T getBean(Class<T> clazz) {T bean = getApplicationContext().getBean(clazz);return bean;}}

3.2 测试

老样子,为了方便阅读,我决定省略测试内容,直接说测试结果。

  1. 在普通类中使用,失败,获取的测试Bean是一个null
  2. 在Controller中直接将该类作为Bean@Autowired进去(因为@Service注解就想到了),获取Bean成功
  3. 我也尝试了一些其他的办法在普通类中使用,均失败了,有好办法的话告诉我吧。



方式 4 | 继承WebApplicationObjectSupport

!!不推荐!!

与**[方式3]**一样,它也只能在Bean中使用,因此也很不推荐。


### 4.1 实现
@Service
public class SpringContextUtil extends WebApplicationObjectSupport {public <T> T getBean(Class<T> clazz) {T bean = getApplicationContext().getBean(clazz);return bean;}}

4.2 测试

同[方式3],略。



方式 5 | 通过WebApplicationContextUtils

!!不推荐!!

适用于web项目的b/s结构。只适合获取web项目中。

补充:该bean 定义对应于单个websocket 的生命周期。该作用域仅适用于WebApplicationContext环境。


5.1 实现

  1. SpringContextUtil代码
public class SpringContextUtil {public static <T> T getBean(ServletContext request, String name, Class<T> clazz){WebApplicationContext webApplicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(request);// 或者WebApplicationContext webApplicationContext1 = WebApplicationContextUtils.getWebApplicationContext(request);
//        webApplicationContext1.getBean(name, clazz)T bean = webApplicationContext.getBean(name, clazz);return bean;}}

5.2 测试

  1. 首先第一个参数不能传递null,否则会报错
  2. 暂时没有这种场景,后面我就没测(偷懒




致谢

感谢 华为云 | springboot获取bean的几种常用方式 对本博客的帮助

相关文章:

[SpringBoot]如何在一个普通类中获取一个Bean

最近在项目中出现了一个这种情况&#xff1a;我一顿操作猛如虎的写了好几个设计模式&#xff0c;然后在设计模式中的类中想将数据插入数据库&#xff0c;因此调用Mapper持久层&#xff0c;但是数据怎么都写不进去&#xff0c;在我一顿操作猛如虎的查找下&#xff0c;发现在普通…...

[ERROR] 不再支持目标选项 5。请使用 7 或更高版本

在编译spirng boot 3.x版本时,出现了以下错误. 出现这个错误: [ERROR] COMPILATION ERROR : [INFO] -------------------------------------------- [ERROR] 不再支持源选项 5。请使用 7 或更高版本。 [ERROR] 不再支持目标选项 5。请使用 7 或更高版本。 要指定版本: 解决办…...

EasyMR:为 AI 未来赋能,打造弹性大数据引擎的革命

如果要评一个2023科技圈的热搜榜&#xff0c;那么以人工智能聊天机器人 ChatGPT 为代表的 AI大模型 绝对会霸榜整个2023。 ChatGPT 于2022年11月30日发布。产品发布5日&#xff0c;注册用户数就超过100万。推出仅两个月后&#xff0c;它在2023年1月末的月活用户已经突破了1亿&…...

C //练习 4-10 另一种方法是通过getline函数读入整个输入行,这种情况下可以不使用getch与ungetch函数。请运用这一方法修改计算器程序。

C程序设计语言 &#xff08;第二版&#xff09; 练习 4-10 练习 4-10 另一种方法是通过getline函数读入整个输入行&#xff0c;这种情况下可以不使用getch与ungetch函数。请运用这一方法修改计算器程序。 注意&#xff1a;代码在win32控制台运行&#xff0c;在不同的IDE环境下…...

竞赛保研 基于深度学习的行人重识别(person reid)

文章目录 0 前言1 技术背景2 技术介绍3 重识别技术实现3.1 数据集3.2 Person REID3.2.1 算法原理3.2.2 算法流程图 4 实现效果5 部分代码6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习的行人重识别 该项目较为新颖&#xff0c;适合…...

Ncast盈可视 高清智能录播系统 IPSetup.php信息泄露+RCE漏洞复现(CVE-2024-0305)

0x01 产品简介 Ncast盈可视 高清智能录播系统是广州盈可视电子科技有限公司一种先进的音视频录制和播放解决方案,旨在提供高质量、高清定制的录播体验。该系统采用先进的摄像和音频技术,结合强大的软件平台,可以实现高清视频录制、多路音频采集、实时切换和混音、定制视频分…...

GO语言Context的作用

文章目录 Context为什么需要Context多任务超时例子Context结构 Context各种使用方法创建contextvalueCtxvalueCtx结构体WithValue cancelCtxcancelCtx结构体withCancel timerCtxWithDeadlineWithTimeout 总结 Context 为什么需要Context Go语言需要Context主要是为了在并发环…...

金和OA C6 upload_json 任意文件上传漏洞

产品介绍 金和网络是专业信息化服务商,为城市监管部门提供了互联网监管解决方案,为企事业单位提供组织协同OA系统开发平台,电子政务一体化平台,智慧电商平台等服务。 漏洞概述 金和 OA C6 upload_json接口处存在任意文件上传漏洞&#xff0c;攻击者可以通过构造特殊请求包上…...

大模型学习第四课

学习目标&#xff1a; XTuner 大模型单卡低成本微调实战 学习内容&#xff1a; Finetune简介XTuner介绍8GB显卡玩转LLM动手实战环节 学习时间&#xff1a; 20240110 学习产出&#xff1a; Finetune简介 增量预训练微调指令跟随微调LoRA,QLoRAXTuner 简介&#xff1a;适配多…...

Code Runner使用外部控制台,运行结束后等待用户输入

问题描述 网上让程序运行结束暂停的方法大多数只有两种&#xff1a; 1.末尾加上system(“pause”) 2.start /k cmd 第一种方法每一个程序都需要在最后加上这条命令很烦&#xff1b; 第二章方法cmd窗口在程序运行结束后不会自动关闭&#xff0c;需要用户手动关闭 我想找到一种…...

IC设计的前端和后端是如何区分的?

一、工作着重点不同 **1、IC前端&#xff1a;**根据芯片规格书完成SOC的设计和集成&#xff0c; 使用仿真验证工具完成SOC的设计验证。 **2、IC后端&#xff1a;**将前端设计产生的门级网表通过EDA设计工具进行布局布线和进行物理验证并最终产生供制造用的GDSII数据 二、工作…...

Unity WebView 中文输入支持

使用版本&#xff1a;Vuplex 3D WebView for Windows v4.4&#xff1b; 测试环境&#xff1a;unity editor 2020.3.40f1c1、Windows&#xff1b; 1、打开脚本CanvasWebVie!wPrefab 2、找到_initCanvasPrefab方法&#xff0c;约略在459行附近 3、添加一行代码&#xff1a; …...

x-cmd pkg | trdsql - 能对 CSV、LTSV、JSON 和 TBLN 执行 SQL 查询的工具

目录 简介首次用户技术特点竞品和相关作品进一步阅读 简介 trdsql 是一个使用 sql 作为 DSL 的强大工具: 采用 SQL 对 CSV、LTSV、JSON 和 TBLN 文件执行查询与 MySQL&#xff0c;Postgresql&#xff0c;Sqlite 的 Driver 协同&#xff0c;可以实现对应数据库的表与文件的 JO…...

Camunda Spin

Spin 常用于在脚本中解析json或者xml使用&#xff0c;S(variable) 表示构造成Spin对象&#xff0c;通过prop(“属性名”)获取属性值&#xff0c;通过stringValue()、numberValue()、boolValue() 等对类型转换。 repositoryService.createDeployment().name("消息事件流程&…...

strlen/Memcpy_s/strncasecmp

strlen 声明&#xff1a;size_t strlen(const char *str) 举例&#xff1a; #include <stdio.h> #include <string.h>int main () {char str[50];int len;strcpy(str, "This is runoob.com");len strlen(str);printf("|%s| 的长度是 |%d|\n"…...

水经微图安卓版APP正式上线!

在水经微图APP&#xff08;简称“微图APP”&#xff09;安卓版已正式上线&#xff01; 在随着IOS版上线约一周之后&#xff0c;安卓版终于紧随其后发布了。 微图安卓版APP下载安装 自从IOS版发布之后&#xff0c;就有用户一直在问安卓版什么时候发布&#xff0c;这里非常感谢…...

数据结构第十二弹---堆的应用

堆的应用 1、堆排序2、TopK问题3、堆的相关习题总结 1、堆排序 要学习堆排序&#xff0c;首先要学习堆的向下调整算法&#xff0c;因为要用堆排序&#xff0c;你首先得建堆&#xff0c;而建堆需要执行多次堆的向下调整算法。 但是&#xff0c;使用向下调整算法需要满足一个前提…...

[NSSRound#3 Team]This1sMysql

[NSSRound#3 Team]This1sMysql 源码 <?php show_source(__FILE__); include("class.php"); $conn new mysqli();if(isset($_POST[config]) && is_array($_POST[config])){foreach($_POST[config] as $key > $val){$value is_numeric($var)?(int)$…...

Android 通知简介

Android 通知简介 1. 基本通知 图1: 基本通知详情 小图标 : 必须提供,通过 setSmallIcon( ) 进行设置.应用名称 : 由系统提供.时间戳 : 由系统提供,也可隐藏时间.大图标(可选) : 可选内容(通常仅用于联系人照片,请勿将其用于应用图标),通过setLargeIcon( ) 进行设置.标题 : 可选…...

QT开发 2024最新版本优雅的使用vscode开发QT

▬▬▬▬▬▶VS开发QT◀▬▬▬▬▬ &#x1f384;先看效果 &#x1f384;编辑环境变量 如图添加环境变量&#xff01;&#xff01;&#xff01; 东西全在QT的安装目录&#xff01;&#xff01;&#xff01; 找到的按照我的教程再装一次&#xff01;&#xff01;&#xff01; 点…...

浅谈 React Hooks

React Hooks 是 React 16.8 引入的一组 API&#xff0c;用于在函数组件中使用 state 和其他 React 特性&#xff08;例如生命周期方法、context 等&#xff09;。Hooks 通过简洁的函数接口&#xff0c;解决了状态与 UI 的高度解耦&#xff0c;通过函数式编程范式实现更灵活 Rea…...

19c补丁后oracle属主变化,导致不能识别磁盘组

补丁后服务器重启&#xff0c;数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后&#xff0c;存在与用户组权限相关的问题。具体表现为&#xff0c;Oracle 实例的运行用户&#xff08;oracle&#xff09;和集…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程&#xff0c;它的核心机制是 Goroutine 协程、Channel 通道&#xff0c;并基于CSP&#xff08;Communicating Sequential Processes&#xff0…...

鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/

使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题&#xff1a;docker pull 失败 网络不同&#xff0c;需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

IT供电系统绝缘监测及故障定位解决方案

随着新能源的快速发展&#xff0c;光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域&#xff0c;IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选&#xff0c;但在长期运行中&#xff0c;例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...