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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在WindowsServer2012中部署war项目

目录 前言 一.jdk安装 二.Tomact安装 三.MySQL安装 ​编辑​编辑​编辑​编辑​编辑​编辑​编辑 四.开放端口号 MySQL开放端口号 Tomact开放端口号 ​编辑 五.项目部署 1.将war放置在tomact中 2.配置项目sql脚本 3.最终效果 前言 安装Java开发工具包&#xff08…

【libpcap】获取报文pcap的ns级别的时间戳

1.安装libpcap 首先&#xff0c;下载最新的 libpcap 源代码。你可以从 tcpdump.org 获取最新版本 1 解压下载的libpcap tar -zxvf libpcap-version.tar.gz 2 进入解压目录进行安装 cd libpcap-version ./configure make sudo make install2 解析报文时间戳 #include <pca…

力扣 2707.字符串中的额外字符(动态规划)

力扣 2707.字符串中的额外字符 动态规划 f[0] 0; s字符串长度为n&#xff0c;求f[n] f[n] ((f[n - 1] 1) < f[j : n]) ? (f[n - 1] 1) : f[j : n]; (其中 j < n) 其中f[j : n]为字符串第j位到第n位&#xff0c;这里需要满足f[j : n]为字典中所出现的字符串 因此&…

Linux进阶命令使用

在 Linux 中&#xff0c;除了常用的基础命令&#xff0c;有一系列进阶命令可以帮助用户更有效地管理系统和执行复杂的任务。以下是一些常见的 Linux 进阶命令及其用法&#xff1a; 文本处理 grep&#xff1a;搜索文本并打印匹配的行。 grep pattern filenameawk&#xff1a;用…

Fancy

专门记录一点思维题。 1. 反转与双端队列&#xff1a;LC 2810 故障键盘 这题是个easy&#xff0c;但用StringBuilder强行模拟反转就没意思了。 可以这么想&#xff0c;当打出一个i&#xff0c;代表一个控制信号&#xff0c;反转。 一开始我们向队列尾部&#xff08;屏幕上的…

SpringMVC 学习博客记录

文章目录 Servlet请求转发和请求包含RequestDispatcher HandlerInterceptor组件实际运用场景 HandlerMapping&RequestMappingInfo(HandlerMapping)HandlerExecutionChainHandlerAdapter源码学习知识点博客记录 Servlet请求转发和请求包含 RequestDispatcher Request#getR…

文件上传进阶绕过技巧(一)和靶场实战

★★免责声明★★ 文章中涉及的程序(方法)可能带有攻击性&#xff0c;仅供安全研究与学习之用&#xff0c;读者将信息做其他用途&#xff0c;由Ta承担全部法律及连带责任&#xff0c;文章作者不承担任何法律及连带责任。 0、环境准备 请移步《文件上传靶场实战&#xff1a;upl…

数据库的数据会存到文件中

数据库的数据会存到文件中。文件就是操作系统对磁盘block的映射。 文件/块在开头有元数据&#xff0c;包含eof的位置&#xff0c;recode的数量&#xff0c;每个recode的长度。 聚集索引和数据放在一起&#xff0c;索引就是数据主键。 而非聚集索引在另一个地址中单独存储&…

从零学Java 泛型

Java 泛型 文章目录 Java 泛型1 什么是泛型?2 泛型类3 泛型接口4 泛型方法5 泛型集合 Collection 工具类 1 什么是泛型? Java泛型是JDK1.5中引入的一个新特性&#xff0c;其本质是参数化类型&#xff0c;把类型作为参数传递。 常见形式有泛型类、泛型接口、泛型方法。 语法…

SPI接口协议

SPI接口协议 SPI(Serial Peripheral Interface)是由Motorola公司定义的接口协议标准&#xff0c;串行外设接口(SPI)是微控制器和外围IC&#xff08;如传感器、 ADC、 DAC、移位寄存器、 SRAM等&#xff09;之间使用最广泛的接口之一。SPI是一种同步、全双工、主从式接口&#x…

你了解计算机网络的发展历史吗?

1.什么是计算机网络 计算机网络是指将一群具有独立功能的计算机通过通信设备以及传输媒体被互联起来的&#xff0c;在通信软件的支持下&#xff0c;实现计算机间资源共享、信息交换或协同工作的系统。计算机网络是计算机技术与通信技术紧密结合的产物&#xff0c;两者的迅速发展…

Lua调用dll(C#)的代码示例

以下是一个简单的示例&#xff0c;演示如何在Lua中调用.NET Framework的DLL。请注意&#xff0c;这个示例假设你已经安装了Lua和.NET Framework&#xff0c;并且有一个名为"MyDll.dll"的.NET DLL。 首先&#xff0c;创建一个名为"MyDll.cs"的C#文件&#…

11853 - Paintball (UVA)

题目链接如下&#xff1a; Online Judge 这道题挺可惜&#xff0c;我思路其实就差了一点点没想出来&#xff0c;还是看了uva 11853 paintball&#xff08;好题&#xff09;——yhx_yhx. live-CSDN博客 这里的文字部分才最终写出来。 dfs版本代码如下&#xff1a; #include …

C++系列十五:字符串

字符串 1 、创建和初始化C字符串2. C字符串的常用操作3. C字符串处理函数4. C字符串在实际开发中的应用 C中的字符串是由字符组成的序列。字符串常用于处理文本数据&#xff0c;例如用户输入、文件内容等。C标准库提供了一个名为std::string的类&#xff0c;用于表示和处理字符…

递归——简单粗暴的问题解决方式

相信很多人在刚接触算法时都在递归上栽过跟头&#xff08;包括我&#xff09;&#xff0c;但是在掌握了这项技能后会有种豁然开朗的感觉&#xff01; 我用我自己&#xff01; 怎么会有这么优雅而又简单粗暴的解决问题的方法&#xff01; \color{red}{怎么会有这么优雅而又简单…

爬虫之牛刀小试(三):爬取中国天气网全国天气

天气网&#xff1a; import requests from bs4 import BeautifulSoup import time from pyecharts.charts import Bar from pyecharts import options as optsurl_hb http://www.weather.com.cn/textFC/hb.shtml url_db http://www.weather.com.cn/textFC/db.shtml url_hd …

Java SE入门及基础(6)

运算符 1.常规运算符&#xff08; - * /&#xff09; 示例 /** * 运算符操作 - * / */ public class Example2 { public static void main ( String [] args ) { //变量在使用之前必须完成初始化操作。换言之就是给变量赋值。 // int a, b; // a 5; // b …

跨境电商之店群模式:Shopee店群是什么?卖家如何做好店群?

今天跟大家谈一谈越来越火爆的店群模式&#xff0c;现在大部分做跨境电商的卖家都会建立自己的店群&#xff0c;其中很多做 Shopee的卖家时常会听到一个名词“ Shopee 店群模式”&#xff0c;但很多人都不知道怎么去做&#xff0c;或者在犹豫要不要做&#xff0c;所以东哥我会从…

mac上cmake编译的库A,给其他库B使用报错ld64.lld: error

ld64.lld: error xxxx.a(xxx.c.o) has version 13.5.0, which is newer than target minimum of 10.11.0 根本原因&#xff1a; 在mac上编译库B时&#xff0c;macosx-version-min为10.11&#xff0c;即macosx sdk的最低版本 所以要求cmake编译的库A也应该指定macosx-version-…

谈谈Spring Bean

一、IoC 容器 IoC 容器是 Spring 的核心&#xff0c;Spring 通过 IoC 容器来管理对象的实例化和初始化&#xff08;这些对象就是 Spring Bean&#xff09;&#xff0c;以及对象从创建到销毁的整个生命周期。也就是管理对象和依赖&#xff0c;以及依赖的注入等等。 Spring 提供…