[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 {

    @Autowired
    private 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;

    @Override
    public 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的几种常用方式 对本博客的帮助

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/301258.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JVM工作原理与实战(六):类的生命周期-连接阶段

专栏导航 JVM工作原理与实战 RabbitMQ入门指南 从零开始了解大数据 目录 专栏导航 前言 一、类的生命周期 1.加载&#xff08;Loading&#xff09; 2.连接&#xff08;Linking&#xff09; 3.初始化&#xff08;Initialization&#xff09; 4.使用&#xff08;Using&…

目标检测开源数据集——海底垃圾识别

随着全球经济的快速发展&#xff0c;海洋垃圾问题日益严重。海洋垃圾不仅对海洋生态系统造成严重破坏&#xff0c;还威胁到人类的健康和生存。因此&#xff0c;海上垃圾识别变得至关重要。本文将详细介绍海上垃圾识别的重要性&#xff0c;从生态、经济、健康和社会四个方面进行…

机器学习原理到Python代码实现之LinearRegression

Linear Regression 线性回归模型 该文章作为机器学习的第一篇文章&#xff0c;主要介绍线性回归模型的原理和实现方法。 更多相关工作请参考&#xff1a;Github 算法介绍 线性回归模型是一种常见的机器学习模型&#xff0c;用于预测一个连续的目标变量&#xff08;也称为响应变…

matlab如何标定相机内外参和畸变参数

关于内外参矩阵和畸变矩阵可以学习 https://blog.csdn.net/qq_30815237/article/details/87530011?spm1001.2014.3001.5506 在APP中找到 camera Calibrator 点击 Add Images&#xff0c;导入拍照图片。标定20张左右就够了&#xff0c;然后角度变一下&#xff0c;但不需要变太…

向量数据库:usearch的简单使用+实现图片检索应用

usearch的简单使用 usearch是快速开源搜索和聚类引擎&#xff0c;用于C、C、Python、JavaScript、Rust、Java、Objective-C、Swift、C#、GoLang和Wolfram &#x1f50d;中的向量和&#x1f51c;字符串 // https://github.com/unum-cloud/usearch/blob/main/python/README.md …

20240107让Firefly的AIO-3399J开发板的Android11下配置为默认1080p录像

20240107让Firefly的AIO-3399J开发板的Android11下配置为默认1080p录像 2024/1/7 23:01 开发板&#xff1a;Firefly的AIO-3399J【RK3399】 SDK&#xff1a;rk3399-android-11-r20211216.tar.xz【Android11】 Android11.0.tar.bz2.aa【ToyBrick】 Android11.0.tar.bz2.ab Androi…

【Unity美术】如何用3DsMax做一个水桶模型

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

让充电器秒供多个快充口,乐得瑞推出1拖2功率分配快充线方案

随着PD3.1协议的市场应用越来越多&#xff0c;一些充电器的Type-C接口的输出功率达到百瓦及以上&#xff0c;如何充分利用好这类充电器设备&#xff0c;乐得瑞电子推出1拖2快充线缆解决方案&#xff0c;支持智能功率分配策略支持私有快充协议。 如上图是乐得瑞1拖2功率分配快充…

二叉树与堆的深度解析:数据结构中的关键概念及应用

. 个人主页&#xff1a;晓风飞 专栏&#xff1a;数据结构|Linux|C语言 路漫漫其修远兮&#xff0c;吾将上下而求索 文章目录 前言树概念注意&#xff1a; 树的基本概念及术语基本概念及术语以家谱为例 树的表示孩子兄弟表示法简介优势应用示例 树在实际中的运用文件系统的目录树…

Verilog学习记录

目录 一、Verilog简介 &#xff08;一&#xff09;Verilog 的主要特性 &#xff08;二&#xff09;Verilog的主要应用 &#xff08;三&#xff09;Verilog设计方法 二、Verilog基础语法 &#xff08;一&#xff09;标识符和关键字 &#xff08;二&#xff09;Verilog数据…

创建Vue3项目

介绍 使用命令创建vue3项目 示例 第一步&#xff1a;执行创建项目命令 npm create vuelatest第二步&#xff1a;填写输入项 第三步&#xff1a;进入study-front-vue3文件夹 cd study-front-vue3第四步&#xff1a;执行npm命令安装依赖 npm install第五步&#xff1a;运行…

LLM 幻觉现象及 RAG 解决方案

1. 幻觉现象及原因 什么是幻觉(hallucination)现象? 大模型的回答有编造成分或错误. 比如问 “tensorflow 1.12 版本有 xxx 这个api 么”, 模型回答 “有”, 其实没有. 原因 训练语料质量低, 本身有错误答案存在.LLM 的训练并不关注 “事实是否正确”, 自然不能保证生成答案一…

OpenMMlab导出PointPillars模型并用onnxruntime推理

导出onnx文件 通过mmdeploy的tool/deploy.py脚本容易转换得到PointPillars的end2end.onnx模型。 根据https://github.com/open-mmlab/mmdeploy/blob/main/docs/zh_cn/04-supported-codebases/mmdet3d.md显示&#xff0c;截止目前 mmdet3d 的 voxelize 预处理和后处理未转成 o…

【APACHE】的认识和基础配置参数

#主页传送:江南的江 #每日鸡汤&#xff1a;人生没有如果和假设&#xff0c;只有后果和结果。生活有进有退&#xff0c;输什么也不能输心情。生活简单就是迷人的&#xff0c;学会简单其实就是不简单。要学会平静地接受现实&#xff0c;学会对自己说声顺其自然&#xff0c;学会坦…

Selenium安装WebDriver:ChromeDriver谷歌浏览器驱动下载安装与使用最新版118/119/120

Selenium安装WebDriver&#xff1a;ChromeDriver谷歌浏览器驱动下载安装与使用最新版118/119/120 0. 背景 在使用之前的代码通过selenium操作Chrome浏览器时&#xff0c;安装中遇到了Chrome版本与浏览器驱动不匹配的的问题&#xff0c;在此记录安装下过程 1. 确定Chrome版本 …

海外跨境独立站和代购系统存在必然联系?独立站建站初期,以及如何运营好独立站。

海外跨境独立站和代购系统在多个方面存在差异&#xff1a; 定位&#xff1a;独立站是拥有独立域名&#xff0c;自主宣传推广媒体与渠道的新型网站&#xff0c;更侧重于培养买家&#xff0c;做品牌建设&#xff0c;相当于个体经营专卖店。而代购系统是利用先进的技术和流程管理…

3D软件坐标系速查【左手/右手】

本文介绍不同3D软件的世界坐标系之间的差异及其工作原理。 NSDT工具推荐&#xff1a; Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REVIT导出3D模型插件 - 3D模型语义搜索引擎 基本上&#xff0c;游戏引擎和3…

【大数据进阶第三阶段之Datax学习笔记】阿里云开源离线同步工具Datax概述

【大数据进阶第三阶段之Datax学习笔记】阿里云开源离线同步工具Datax概述 【大数据进阶第三阶段之Datax学习笔记】阿里云开源离线同步工具Datax快速入门 【大数据进阶第三阶段之Datax学习笔记】阿里云开源离线同步工具Datax类图 【大数据进阶第三阶段之Datax学习笔记】使用…

第11课 利用windows API捕获桌面图像并通过FFmpeg分享

在上一章&#xff0c;我们已经实现了一对一音视频对话功能。在实际应用中&#xff0c;我们常需要把自己的电脑桌面分享给他人以实现桌面共享功能&#xff0c;这种功能在视频会议、在线教学等场景中很常见&#xff0c;这种功能如何实现呢&#xff1f;这节课我们就来解决这个问题…

python opencv怎么安装

1、安装python 注意&#xff1a;windows10 安装时强烈建议不用使用 Windows Store 安装。避免后期python运行时牵扯权限相关问题。 具体步骤&#xff1a; 1、前往python官网下载windows python 安装包 2、双击运行安装&#xff08;强力建议自定义安装&#xff0c;勾选pip&#…