[SpringBoot]如何在一个普通类中获取一个Bean
最近在项目中出现了一个这种情况:我一顿操作猛如虎的写了好几个设计模式,然后在设计模式中的类中想将数据插入数据库,因此调用Mapper持久层,但是数据怎么都写不进去,在我一顿操作猛如虎的查找下,发现在普通类中用@Autowired
注入的Bean是Null,也就是说注入失败了,瞎搞。
针对以上情况,我做了三种解决方案,经测试均可行,解决方案如下:
- 在设计模式中只操作数据,最后还是将数据返回给Controller层,再由Controller向下调用写入数据库
- 简化设计模式,然后将其注册为Service,然后再Service中调用Mapper层
- 通过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代码如下:
- Bean代码
@Component
public class TestComponent {public String say() {System.out.println("执行成功");return "执行成功";}}
在以上代码中,我们将TestComponent
注册成为了一个Bean,为了严禁,我们还需要在Controller中调用一下这个类的方法测试一下该类是否真的被注入进去了,但是为了文章不要太冗余,这一块内容我省略掉,结论是:我测试过,是可以在Controller中调用的。
- 通过普通类调用该Bean
实现思想:我们写一个普通的类,在Controller中new出该类的对象,然后在该普通类中@Autowired
的方式注入该类并调用
验证方式:首先,我们会输出该Bean的地址,如果注入成功的话,我们会得到一长串字符,其次,如果成功的话页面与控制台均有输出
-
Controller层
只写个方法了,类信息略
@GetMapping("/com")
public String common() {CommonClazz clazz = new CommonClazz();return clazz.say();
}
- 普通类
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 使用
与方式一相比Controller
与CommonClass
类并没有发生太大的变化,但是为了更好的阅读性,我们还是全都展示出来。
- Controller类(依旧省略类信息,只写方法)
@GetMapping("/com")
public void common() {CommonClazz clazz = new CommonClazz();clazz.say();
}
CommonClazz
类
public class CommonClazz {public void say() {TestComponent bean = SpringContextUtil.getBean(TestComponent.class);System.out.println("-----Bean:"+bean);bean.say();}}
- Bean类省略,可以去前面复制
浏览器访问Controller层地址,信息正常输出,内容如下
可以看到Bean的地址被正确输出(说明不是null),也输出了Bean中方法的内容,说明Bean被正常注入了。
方式 2
!推荐!
这种实现可以在任意类中获取一个Bean,但是要修改SpringBoot启动类,并且在获取Bean的时候要传入两个参数,有点冗余,个人觉得使用起来不如方式1(当然也可以通过改写
getBean()
方法的方式只传入一个Bean)。
### 2.1 实现
- 首先我们要简单改造一下SpringBoot启动类,变动如下:
@SpringBootApplication
public class JimTestApplication {public static void main(String[] args) {ConfigurableApplicationContext run = SpringApplication.run(JimTestApplication.class, args);SpringContextUtil.setAc(run);}}
- 其次,我们创建一个
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 使用
- Controller类
new CommonClazz()
(依旧省略类信息,直接写方法)
@GetMapping("/com")
public void common() {CommonClazz clazz = new CommonClazz();clazz.say();
}
CommonClazz
类信息如下
public class CommonClazz {public void say() {// 使用如下TestComponent bean = SpringContextUtil.getBean("testComponent",TestComponent.class);System.out.println("-----Bean:"+bean);bean.say();}}
Bean(TestComponent)
没有做多大的改动,只是有返回值改成void了,为了节省篇幅,这里也省略不写了。
我们在浏览器调用Controller的地址之后,控制台得到如下输出:
结论:Bean被正确注入
方式 3 | 继承ApplicationObjectSupport
的方式获取Bean
!!不推荐!!
这是一种比较鸡肋的方法,使用起来有很大的局限性:它只能在Bean中使用。因为它本身也需要作为Bean被注入后才能生效。
3.1 实现
SpringContextUtil
类内容如下
@Service
public class SpringContextUtil extends ApplicationObjectSupport {public <T> T getBean(Class<T> clazz) {T bean = getApplicationContext().getBean(clazz);return bean;}}
3.2 测试
老样子,为了方便阅读,我决定省略测试内容,直接说测试结果。
- 在普通类中使用,失败,获取的测试Bean是一个
null
- 在Controller中直接将该类作为Bean
@Autowired
进去(因为@Service
注解就想到了),获取Bean成功 - 我也尝试了一些其他的办法在普通类中使用,均失败了,有好办法的话告诉我吧。
方式 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 实现
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 测试
- 首先第一个参数不能传递
null
,否则会报错 - 暂时没有这种场景,后面我就没测(偷懒
致谢
感谢 华为云 | springboot获取bean的几种常用方式 对本博客的帮助
相关文章:

[SpringBoot]如何在一个普通类中获取一个Bean
最近在项目中出现了一个这种情况:我一顿操作猛如虎的写了好几个设计模式,然后在设计模式中的类中想将数据插入数据库,因此调用Mapper持久层,但是数据怎么都写不进去,在我一顿操作猛如虎的查找下,发现在普通…...
[ERROR] 不再支持目标选项 5。请使用 7 或更高版本
在编译spirng boot 3.x版本时,出现了以下错误. 出现这个错误: [ERROR] COMPILATION ERROR : [INFO] -------------------------------------------- [ERROR] 不再支持源选项 5。请使用 7 或更高版本。 [ERROR] 不再支持目标选项 5。请使用 7 或更高版本。 要指定版本: 解决办…...

EasyMR:为 AI 未来赋能,打造弹性大数据引擎的革命
如果要评一个2023科技圈的热搜榜,那么以人工智能聊天机器人 ChatGPT 为代表的 AI大模型 绝对会霸榜整个2023。 ChatGPT 于2022年11月30日发布。产品发布5日,注册用户数就超过100万。推出仅两个月后,它在2023年1月末的月活用户已经突破了1亿&…...
C //练习 4-10 另一种方法是通过getline函数读入整个输入行,这种情况下可以不使用getch与ungetch函数。请运用这一方法修改计算器程序。
C程序设计语言 (第二版) 练习 4-10 练习 4-10 另一种方法是通过getline函数读入整个输入行,这种情况下可以不使用getch与ungetch函数。请运用这一方法修改计算器程序。 注意:代码在win32控制台运行,在不同的IDE环境下…...

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

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接口处存在任意文件上传漏洞,攻击者可以通过构造特殊请求包上…...
大模型学习第四课
学习目标: XTuner 大模型单卡低成本微调实战 学习内容: Finetune简介XTuner介绍8GB显卡玩转LLM动手实战环节 学习时间: 20240110 学习产出: Finetune简介 增量预训练微调指令跟随微调LoRA,QLoRAXTuner 简介:适配多…...
Code Runner使用外部控制台,运行结束后等待用户输入
问题描述 网上让程序运行结束暂停的方法大多数只有两种: 1.末尾加上system(“pause”) 2.start /k cmd 第一种方法每一个程序都需要在最后加上这条命令很烦; 第二章方法cmd窗口在程序运行结束后不会自动关闭,需要用户手动关闭 我想找到一种…...
IC设计的前端和后端是如何区分的?
一、工作着重点不同 **1、IC前端:**根据芯片规格书完成SOC的设计和集成, 使用仿真验证工具完成SOC的设计验证。 **2、IC后端:**将前端设计产生的门级网表通过EDA设计工具进行布局布线和进行物理验证并最终产生供制造用的GDSII数据 二、工作…...

Unity WebView 中文输入支持
使用版本:Vuplex 3D WebView for Windows v4.4; 测试环境:unity editor 2020.3.40f1c1、Windows; 1、打开脚本CanvasWebVie!wPrefab 2、找到_initCanvasPrefab方法,约略在459行附近 3、添加一行代码: …...

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

Camunda Spin
Spin 常用于在脚本中解析json或者xml使用,S(variable) 表示构造成Spin对象,通过prop(“属性名”)获取属性值,通过stringValue()、numberValue()、boolValue() 等对类型转换。 repositoryService.createDeployment().name("消息事件流程&…...
strlen/Memcpy_s/strncasecmp
strlen 声明:size_t strlen(const char *str) 举例: #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(简称“微图APP”)安卓版已正式上线! 在随着IOS版上线约一周之后,安卓版终于紧随其后发布了。 微图安卓版APP下载安装 自从IOS版发布之后,就有用户一直在问安卓版什么时候发布,这里非常感谢…...

数据结构第十二弹---堆的应用
堆的应用 1、堆排序2、TopK问题3、堆的相关习题总结 1、堆排序 要学习堆排序,首先要学习堆的向下调整算法,因为要用堆排序,你首先得建堆,而建堆需要执行多次堆的向下调整算法。 但是,使用向下调整算法需要满足一个前提…...

[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◀▬▬▬▬▬ 🎄先看效果 🎄编辑环境变量 如图添加环境变量!!! 东西全在QT的安装目录!!! 找到的按照我的教程再装一次!!! 点…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)
2025年能源电力系统与流体力学国际会议(EPSFD 2025)将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会,EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...

OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

uniapp手机号一键登录保姆级教程(包含前端和后端)
目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号(第三种)后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...