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://www.mzph.cn/news/702191.shtml

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

相关文章

matlab悬臂梁有限元分析

1、内容简介 略 47-可以交流、咨询、答疑 2、内容说明 略 建模说明 设计一个长方体的悬臂梁&#xff0c;长宽高分别为100m、10m和15m&#xff0c;材料特性为杨氏模量2e5&#xff0c;泊松比0.3&#xff0c; Matlab有限元分析&#xff08;截图&#xff09; 上图为悬臂梁的扰度…

Autosar 开篇

背景 AUTOSAR&#xff08;Automotive Open System Architecture&#xff09;是一个跨汽车行业的标准化软件架构&#xff0c;旨在促进汽车电子系统的开发和部署。下面是AUTOSAR发展的一些关键点&#xff1a; 起源和背景&#xff1a; AUTOSAR最初于2003年由汽车制造商宝马、戴姆…

从私人客户转变为教练会员网站

教练和顾问可以做出的最令人兴奋的转变之一就是通过教练会员网站扩大业务规模。 一对多优惠的类型有很多种&#xff0c;但与任何其他选择相比&#xff0c;教练和顾问的会员资格拥有最多的机会和灵活性&#xff0c;可以与你和你的客户一起发展。 世界正在转向更容易获得和更…

Peter算法小课堂—动态规划

Peter来啦&#xff0c;好久没有更新了呢 今天&#xff0c;我们来讨论讨论提高组的动态规划。 动态规划 动态规划有好多经典的题&#xff0c;有什么背包问题、正整数拆分、杨辉三角……但是&#xff0c;如果考到陌生的题&#xff0c;怎么办呢&#xff1f;比如说2000年提高组的…

AD24-Gerber生产文件输出及整理

一、Gerber生产文件输出 1、先进行规则检查 2、Gerber Files输出 3、钻孔文件 4、IPC网表 5、坐标文件 二、Gerber Flies文件整理 1、CAM 2、SMT 3、ASM 4、PRJ 5、DXF

ubuntu安装gptsovits

我看到社区有人需要&#xff0c;刚好我自己也要安装个ubuntu的用在自己的4090服务器上玩一玩。 于是就写一篇这样的教程。但是我只需要他的api推理&#xff0c;用于测试4090合成速度。所以这里只执行Python api.py 环境 1.首先下载整合包&#xff0c;里面有个nltk_data,拿出来…

Jmeter之单接口的性能测试

前言&#xff1a; 服务端的整体性能测试是一个非常复杂的概念&#xff0c;包含生成虚拟用户&#xff0c;模拟并发&#xff0c;分析性能结果等各种技术&#xff0c;期间可能还要解决设计场景、缓存影响、第三方接口mock、IP限制等问题。如何用有限的测试机器&#xff0c;在测试环…

Mysql 连接最近经常报超时

原因 怀疑是某个服务频繁调用mysql操作,导致linux buff/cache 过大 # 通过下列命令查看 free -h解决方案 临时解决方案: 可以通过写入 /proc/sys/vm/drop_caches 来释放缓存。这是一个临时的操作&#xff0c;内核会在需要时再次填充缓存 # 释放缓存 sync; echo 3 > /proc/…

【C语言】详解计算机二级c语言程序题

文章目录 前言资料相关程序题 一&#xff08;字符串&#xff09;程序题 二&#xff08;数组&#xff09;程序题 三&#xff08;基础&#xff09;程序题 四&#xff08;结构体&#xff09;程序题 五&#xff08;结构体&#xff09;程序题 六&#xff08;基础&#xff09; 前言 …

leetcode:491.递增子序列

1.误区&#xff1a;不能直接对数组排序再求解子集&#xff0c;因为那样就改变了原有数组的顺序 2.树形结构&#xff1a;一个一个取数&#xff0c;然后保证是递增序列&#xff0c;且不能重复。&#xff08;数层上不可以重复取&#xff0c;树枝上可以重复取&#xff09;收集的结…

[设计模式Java实现附plantuml源码~行为型]对象间的联动~观察者模式

前言&#xff1a; 为什么之前写过Golang 版的设计模式&#xff0c;还在重新写Java 版&#xff1f; 答&#xff1a;因为对于我而言&#xff0c;当然也希望对正在学习的大伙有帮助。Java作为一门纯面向对象的语言&#xff0c;更适合用于学习设计模式。 为什么类图要附上uml 因为很…

【大模型 数据增强】IEPILE:基于模式的指令生成解法,提高大模型在信息抽取任务上的性能

IEPILE&#xff1a;基于模式的指令生成解法&#xff0c;提高大模型在信息抽取任务上的性能 提出背景基于模式的指令生成解法效果 提出背景 论文&#xff1a;https://arxiv.org/pdf/2402.14710.pdf 代码&#xff1a;https://github.com/zjunlp/IEPile 2024年02月发布了一个大…

MySQL锁三部曲:临键、间隙与记录的奇妙旅程

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 MySQL锁三部曲&#xff1a;临键、间隙与记录的奇妙旅程 前言临键锁的奥秘间隙锁记录锁 前言 在数据库世界中&#xff0c;锁是维护数据完整性的一种关键机制。而MySQL中的临键锁、间隙锁和记录锁则是锁…

Python 读取创建word文档

本篇文章内容为使用python 读取word文档和创建word文档 读取doc文件 引入类库 示例如下&#xff1a; import win32com import win32com.client import os 读取doc文件 通过得到的doc文件路径调用系统word功能。 打开文件获取其中的文本信息&#xff0c;输出文本信息&#…

彩虹全新 SUP 模板,卡卡云模板修复版

彩虹全新 SUP 模板&#xff0c;卡卡云模板&#xff0c;首页美化&#xff0c;登陆页美化&#xff0c;修复了 PC 端购物车页面显示不正常的问题。下载地址&#xff1a;彩虹全新 SUP 模板.zip 模板截图

[ Python+OpenCV+Mediapipe ] 实现对象识别

一、写在前面 本文所用例子为个人学习的小结&#xff0c;如有不足之处请各位多多海涵&#xff0c;欢迎小伙伴一起学习进步&#xff0c;如果想法可在评论区指出&#xff0c;我会尽快回复您&#xff0c;不胜感激&#xff01; 所公布代码或截图均为运行成功后展示。 二、本文内容…

python 条件语句if else

python 条件语句if else Python条件语句是通过一条或多条语句的执行结果&#xff08;True或者False&#xff09;来决定执行的代码块。 可以通过下图来简单了解条件语句的执行过程: Python程序语言指定任何非0和非空&#xff08;null&#xff09;值为true&#xff0c;0 或者…

【C语言基础】:操作符详解(一)

文章目录 操作符详解1. 操作符的分类2. 二进制和进制转换2.1 什么是二进制、八进制、十进制、十六进制2.1.1 二进制和进制转换2.1.2 二进制转十进制2.2.3 二进制转八进制2.2.4 二进制转十六进制 3. 源码、反码、补码4. 移位操作符4.1 左移操作符4.2 右移操作符 5. 位操作符&…

Java学习笔记------继承

继承 Java中提供了一个关键字extends&#xff0c;用这个关键字&#xff0c;我们可以让一个类和另一个类建立继承关系 如图&#xff0c;Student和Teacher类中除了study&#xff08;&#xff09;和teacher&#xff08;&#xff09;两个成员函数不同&#xff0c;其他重复了&…

【摸鱼日常】使用Docker部署2048小游戏

一、本次实践介绍 ​1. 本次实践简介 本次实践部署环境为个人测试环境&#xff0c;快速使用docker部署2048小游戏。 rootWellDone:/home/goodjob# uname -aLinux WellDone 6.5.0-14-generic #14~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Mon Nov 20 18:15:30 UTC 2 x86_64 x86_64…