SpringBoot -【BeanFactory】基础使用及应用场景

1.介绍

在 Spring 框架中,BeanFactory 是 Spring IoC 容器的核心接口,负责管理 bean 的创建、配置和装配。它是 Spring IoC 容器的基础。BeanFactory 接口定义了一系列方法,用于管理和访问容器中的 bean 对象。

BeanFactoryAware 用于在 Spring 容器实例化 Bean 的过程中通知 Bean 实例关联的 BeanFactory 实例。实现了 BeanFactoryAware 接口的 Bean 可以获取对应的 BeanFactory 实例,从而可以在需要时与容器进行交互。

BeanFactoryAware 接口是一个标记接口,如果一个 bean 类实现了 BeanFactoryAware 接口,那么在该 bean 被实例化后,Spring IoC 容器会调用该 bean 的 setBeanFactory() 方法,并传递一个 BeanFactory 实例给这个方法。

换句话说,当一个 bean 实现了 BeanFactoryAware 接口时,它表明它想要获取对 Spring IoC 容器的引用,以便在需要时与容器进行交互。这样的交互可能包括:

  1. 😕 获取其他 bean 实例:通过 BeanFactory 引用,这个 bean 可以动态地获取容器中的其他 bean 实例。
  2. 😕 访问容器的配置信息:通过 BeanFactory,这个 bean 可以访问容器的配置信息,例如属性文件、环境变量等。
  3. 😕 控制 bean 的生命周期:通过 BeanFactory,这个 bean 可以在需要时自定义自己的初始化逻辑,或者在销毁时执行一些清理操作。

因此,BeanFactoryAware 接口为那些需要与 Spring IoC 容器进行交互的 bean 提供了一种标准化的方式,并允许它们在需要时获取对容器的引用,以实现更灵活和可定制的行为。

2.接口定义

[!NOTE]

setBeanFactory(BeanFactory beanFactory) throws BeansException:Spring 容器在实例化 Bean 的过程中会调用该方法,将对应的 BeanFactory 实例传递给实现了 BeanFactoryAware 接口的 Bean。通过该方法,Bean 可以获取并持有对应的 BeanFactory 实例。

package org.springframework.beans.factory;import org.springframework.beans.BeansException;public interface BeanFactoryAware extends Aware {void setBeanFactory(BeanFactory var1) throws BeansException;
}

3.基础使用

在开发中,经常会遇到需要动态加载并管理某些 Bean 的情况,例如根据配置文件、数据库数据或者其他外部条件动态地加载不同的 Bean 实例。这种情况下,可以使用 Spring 的 BeanFactoryAware 接口来实现动态加载 Bean,并将加载的 Bean 实例注册到 Spring 容器中。

3.1 动态加载Bean

通过利用 BeanFactoryAware 接口,使得 DynamicBeanLoader 能够获取到 BeanFactory 实例。然后,在 BusinessService 中,通过 DynamicBeanLoader 将动态创建的 DynamicComponent 注册为 Spring 容器的 Bean。这样,动态加载的 Bean 就能够被 Spring 容器完全管理,

3.1.1 创建动态加载的Bean类

/*** 1.创建动态加载的Bean类* @author 13723* @version 1.0* 2024/2/24 0:22*/
@Component
public class DynamicComponent {private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());public void getConnection(){logger.error("*********** PostgresSQL数据库连接成功!***********");}
}

3.1.2 创建动态加载器类

/*** 创建动态Bean加载配置器类* @author 13723* @version 1.0* 2024/2/24 0:25*/
@Component
public class DynamicBeanLoader implements BeanFactoryAware {/*** 这里选择 ConfigurableListableBeanFactory 作为BeanFactory的实现类* 不选择BeanFactory的原因是因为ConfigurableListableBeanFactory是BeanFactory的子接口* 且ConfigurableListableBeanFactory接口中包含了BeanFactory接口中的所有方法* 且ConfigurableListableBeanFactory接口中还包含了一些扩展方法* 例如:registerSingleton()、registerBeanDefinition()等方法* 通过这些方法可以动态的向Spring容器中注册Bean*/@Resourceprivate ConfigurableListableBeanFactory beanFactory;private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;}/*** 动态加载Bean* @param beanName Bean的名称* @param beanClass Bean的类型*/public void loadBean(String beanName,Class<?> beanClass){beanFactory.registerSingleton(beanName,beanClass);logger.error("*********** 动态加载Bean成功!***********");}
}

3.1.3 在业务类中使用动态加载器

@Service
public class DynamicBeanLoadService {private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());@Autowiredprivate  DynamicBeanLoader dynamicBeanLoader;/*** 通过业务类加载Bean*/public void loadDynamicBean(){logger.error("*********** 通过业务类加载Bean!***********");dynamicBeanLoader.loadBean("dynamicComponentBean",DynamicComponent.class);}}

3.1.4 测试

@SpringBootTest
public class DynamicComponentTest {private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());@Resourceprivate DynamicBeanLoadService dynamicBeanLoadService;@Resourceprivate ApplicationContext context;@Test@DisplayName("测试BeanFactoryAware动态加载Bean")public void getConnection(){// 动态加载BeandynamicBeanLoadService.loadDynamicBean();// 获取并且使用动态BeanDynamicComponent dynamicComponent = context.getBean(DynamicComponent.class);// 调用Bean的连接方法dynamicComponent.getConnection();}
}

在这里插入图片描述

3.2 加载特定目录下的类

在企业级应用中,存在一种需求:需要在系统启动时自动扫描特定目录下的类文件,并将这些类文件加载为 Spring Bean 进行管理。这种情况下,可以使用 BeanFactoryAware 接口来实现自定义的 Bean 加载器,以便动态加载并注册这些类文件对应的 Bean 到 Spring 容器中。

3.2.1 创建自定义Bean加载器类

@Component
public class DynamicLoadClass implements BeanFactoryAware {private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());private ConfigurableListableBeanFactory beanFactory;@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;}// 自定义方法,用于加载指定目录下的类文件并注册为 Spring Beanpublic void loadBeansFromDirectory(String directoryPath) {File directory = new File(directoryPath);if (!directory.exists() || !directory.isDirectory()) {throw new IllegalArgumentException("Directory path is invalid: " + directoryPath);}File[] files = directory.listFiles();if (files != null) {Arrays.stream(files).filter(file -> file.isFile() && file.getName().endsWith(".java")).forEach(file -> {try {//将路径中的 "\\" 替换为包名中的 "."String packageName = file.getPath().substring(file.getPath().indexOf("com"), file.getPath().lastIndexOf("\\")).replace("\\", "."); // 替换掉 xxx.java 中的java 作为类型 用于反射 例如 TUser1.java  -> TUser1String className = file.getName().replace(".java", "");className = packageName + "." + className;// 因为Bean是需要遵循驼峰命名的 所以首字母应该小写 第一个字符小写 后面的进行截断className = Character.toLowerCase(className.charAt(0)) + className.substring(1);Class<?> beanClass = Class.forName(className);Object beanInstance = beanClass.getDeclaredConstructor().newInstance();beanFactory.registerSingleton(beanClass.getSimpleName(), beanInstance);} catch (Exception e) {e.printStackTrace();}});}}
}

3.2.2 测试类

	@Test@DisplayName("测试扫描指定包下的文件加载到Bean")public void loadPage(){String path = "D:\\dcjet\\java_base_study\\src\\main\\java\\com\\hrfan\\java_se_base\\spring_boot\\ss\\bean_factory_avare\\load\\test_bean";// 动态加载BeandynamicLoadClass.loadBeansFromDirectory(path);// 测试指定包的Bean是否加载成功TUser1 bean1 = context.getBean(TUser1.class);TUser2 bean2 = context.getBean(TUser2.class);TUser3 bean3 = context.getBean(TUser3.class);logger.error("bean1:{}",bean1.getClass().getName());logger.error("bean2:{}",bean2.getClass().getName());logger.error("bean3:{}",bean3.getClass().getName());}

在这里插入图片描述

我们利用了 BeanFactoryAware 接口实现了自定义的 Bean 加载器 CustomBeanLoader,它能够从指定目录加载类文件并注册为 Spring Bean。在 Spring Boot 的启动类中,我们通过实现 CommandLineRunner 接口,在系统启动时调用 CustomBeanLoader 加载指定目录下的类文件,并将其注册为 Spring Bean。

4.使用场景

  1. 动态配置管理: 当需要根据外部条件或者运行时状态动态加载和管理一些 Bean 实例时,可以使用 BeanFactoryAware 接口结合动态加载器的方式。
  2. 灵活性要求高: 如果系统要求灵活性高,需要根据用户配置或者运行时条件来动态加载和管理 Bean,这种情况下也适合使用 BeanFactoryAware 接口。
  3. 定制化需求: 在某些特定的场景下,需要定制化的 Bean 加载和管理方式,BeanFactoryAware 接口可以提供更多的灵活性和定制化。

5.优点缺点

5.1 优点:
  1. 灵活性高: 可以根据实际需求动态加载和管理 Bean,提高系统的灵活性和可配置性。
  2. 容器完全管理: 结合 Spring 容器,使用 BeanFactoryAware 接口可以确保动态加载的 Bean 实例被完全纳入 Spring 容器的管理范围。
  3. 解耦合: 使用 BeanFactoryAware 接口可以解耦动态加载逻辑和应用程序的其他部分,提高系统的可维护性和可扩展性。
5.2 缺点:
  1. 复杂性增加: 动态加载 Bean 的逻辑可能会增加系统的复杂性,特别是需要处理动态加载和卸载 Bean 的逻辑时。
  2. 容错性差: 动态加载的 Bean 实例可能会带来一些潜在的安全风险和容错性问题,需要仔细考虑和处理。
  3. 性能影响: 动态加载和管理大量的 Bean 实例可能会对系统的性能产生一定的影响,需要合理评估和处理。

总的来说,使用 BeanFactoryAware 接口实现动态加载 Bean 可以在一定程度上提高系统的灵活性和可配置性,但是也需要谨慎考虑和评估其带来的复杂性和性能影响。适合在对灵活性要求较高、定制化程度较高的场景下使用。

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

相机图像质量研究(39)常见问题总结:编解码对成像的影响--运动模糊

系列文章目录 相机图像质量研究(1)Camera成像流程介绍 相机图像质量研究(2)ISP专用平台调优介绍 相机图像质量研究(3)图像质量测试介绍 相机图像质量研究(4)常见问题总结&#xff1a;光学结构对成像的影响--焦距 相机图像质量研究(5)常见问题总结&#xff1a;光学结构对成…

智慧医疗新篇章:山海鲸可视化引领行业变革

随着科技的不断发展&#xff0c;智慧医疗已经成为医疗行业的新趋势。山海鲸可视化以其独特的视角和前沿的技术&#xff0c;为智慧医疗提供了全方位的解决方案。其强大的数据可视化能力&#xff0c;使得医疗数据更加直观、易于理解。无论是病例分析、手术模拟&#xff0c;还是患…

【GB28181】wvp-GB28181-pro部署安装教程(Ubuntu平台)

目录 前言1 安装依赖2 安装MySQL3 安装redis4 编译ZLMediaKit代码及依赖下载编译运行&#xff08;如果要运行wvp整个项目&#xff0c;这步可以先不执行&#xff09; 5 编译wvp-pro下载源码&#xff08;建议从github上下载&#xff0c;gitee上维护有时候不是很同步&#xff09;编…

半导体物理基础-笔记(续)

源内容参考&#xff1a;https://www.bilibili.com/video/BV11U4y1k7zn/?spm_id_from333.337.search-card.all.click&vd_source61654d4a6e8d7941436149dd99026962 掺杂半导体的费米能级与温度及杂质浓度的关系图 在温度一定的条件下&#xff0c;施主杂质浓度越高&#xff0…

20210505-20240223 CSDN 1024天 创作纪念日

作为一个小白&#xff0c;我没想到自己在不知不觉间就走过了如此长久的一段旅程。恍然间&#xff0c;三年多的时光已经过去了。 机缘 我首次写博客是为了记录日常&#xff0c;分享生活。 在这1024天里&#xff0c;我做了一些记录和分享&#xff0c;特别是遇到一些有趣的、值得…

数据分析在企业培训系统中的关键作用与优势

数据分析在企业培训系统中扮演着关键的角色&#xff0c;它不仅能够帮助企业更好地了解员工培训的需求和效果&#xff0c;还能够提供有针对性的教育方案和提高培训效果。 数据分析可以帮助企业准确把握员工培训需求。通过收集和分析员工的培训需求调查和反馈信息&#xff0c;企…

2024.02.23作业

1. 尝试处理普通信号 #include "test.h"#define MAXSIZE 128void handler(int signo) {if (SIGINT signo){printf("用户按下了 ctrl c 键\n");} }int main(int argc, char const *argv[]) {if (signal(SIGINT, SIG_IGN) SIG_ERR){perror("signal …

Navicat Premium连接Django项目的数据库

首先启动django项目&#xff0c;生成数据库文件 安装依赖 cd backend&#xff08;实际后端的路径&#xff09; pip install -r dev_requirements.txt&#xff08;安装环境&#xff09; 初始化系统 python manage.py migrate&#xff08;生成迁移数据库&#xff09; 运行 python…

Spring 容器、核心容器总结

目录 创建容器获取 bean容器类层次结构图核心容器总结容器相关bean 相关依赖注入相关 创建容器 方式一&#xff1a; 类路径加载配置文件 ApplicationContext ctx new ClassPathXmlApplicationContext("applicationContext.xml");方式二&#xff1a; 文件路径加载配…

Python爬虫实战:图片爬取与保存

引言&#xff1a; 在本文中&#xff0c;我们将学习如何使用Python创建一个简单的图片爬虫。 我们将利用requests库来发送HTTP请求&#xff0c;BeautifulSoup库来解析HTML页面&#xff0c;以及os和shutil库来下载和保存图片。通过这个教程&#xff0c;你将学会如何爬取网…

stable-diffusion-webui安装sd-wav2lip-uhq

按照 https://github.com/numz/sd-wav2lip-uhq/blob/main/README_CN.md 安装即可。 git : https://github.com/numz/sd-wav2lip-uhq.git

在openEuler中通过KVM可视化安装华为FusionCompute的VRM节点

一、说明 本文是华为FusionCompute云平台配置的延续&#xff0c;是在CNA&#xff08;ComputingNode Agent&#xff0c;计算节点代理&#xff09;主机安装配置完成后&#xff0c;详细安装VRM&#xff08;Virtual Resource Manager&#xff0c;虚拟资源管理器&#xff09;节点的…

BlueTooth蓝牙的最新演进版本:BT5.4

现在很多笔记本laptop、电视TV、手机Phone,甚至车机IVI都有了WiFi和蓝牙BT的接入功能。 大约每隔2-3年,就会有一个新版本的蓝牙问世。最新的蓝牙5.4承诺提供比5.3版本更可靠的连接和更高的能效。蓝牙5.4是最新的蓝牙版本,为数千个低能耗节点带来了更高的安全性和高效的连接…

设计推特(Leetcode355)

例题&#xff1a; https://leetcode.cn/problems/design-twitter/ 分析&#xff1a; 推特其实类似于微博&#xff0c;在微博中可以发送文章。 求解这类题目&#xff0c;我们需要根据题目需求&#xff0c;利用面向对象的思想&#xff0c;先对需求做一个抽象&#xff0c;看看能…

【初始RabbitMQ】发布订阅的实现

发布确认原理 生产者将信道设置成 confirm 模式&#xff0c;一旦信道进入 confirm 模式&#xff0c;所有在该信道上面发布的消息都将会被指派一个唯一的 ID(从 1 开始)&#xff0c;一旦消息被投递到所有匹配的队列之后&#xff0c;broker 就会发送一个确认给生产者(包含消息的…

力扣随笔之移除元素(简单27)

思路&#xff1a;定义一个指针left&#xff0c;使该指针及该指针左边的数全部都不等于val&#xff0c;定义一个遍历指针i&#xff0c;若nums[i] val&#xff0c;则i自加&#xff0c;若nums[i] ! val&#xff0c;则将left&#xff0c;并将nums[i]的值赋给nums[left]&#xff0c…

手撕Transformer(三)| 基础Transformer整体结构代码解析,从宏观到微观

文章目录 1 理解重点2 背景介绍 假设3 过程及重要组件3.1 嵌入层和加入位置编码3.2 编码器 Encoder3.3.1 EncoderLayer编码层3.3.2 LayerNorm归一化层 3.3 解码器 Decoder3.4 整合连接Encoder和Decoder 4 完整可运行代码 1 理解重点 在之前一节我们已经介绍了Transformer的位置…

C语言--贪吃蛇

目录 1. 实现目标2. 需掌握的技术3. Win32 API介绍控制台程序控制台屏幕上的坐标COORDGetStdHandleGetConsoleCursorinfoCONSOLE_CURSOR_INFOSetConsoleCursorInfoSetConsoleCursorPositionGetAsyncKeyState 4. 贪吃蛇游戏设计与分析地图<locale.h>本地化类项setlocale函…

14. UE5 RPG使用GameplayTag

GameplayTag本来是应用在GAS游戏技能系统里面的&#xff0c;后来UE直接将其抽离出来&#xff0c;作为一个模块&#xff0c;现在可以不在GAS里也可以使用这个模块。比如&#xff0c;我需要判断一个射线拾取的物体&#xff0c;首先我需要判断这个actor是否存在&#xff0c;然后判…

Nest创建神经元,并显示电压变化曲线

nest 安装与介绍 NEST&#xff08;神经模拟工具&#xff09;最初是在 1990 年代后期开发的。它的主要目标是作为计算神经科学模拟器。它支持具有不同生物学细节水平的各种神经元和突触模型。例如&#xff0c;NEST 的神经元模型范围从泄漏积分和激发模型到详细的 Hodgkin-Huxle…