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

news2024/10/7 4:36:10

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
	 */
	@Resource
	private ConfigurableListableBeanFactory beanFactory;

	private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());


	@Override
	public 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());

	@Autowired
	private  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());
	@Resource
	private DynamicBeanLoadService dynamicBeanLoadService;

	@Resource
	private ApplicationContext context;
	@Test
	@DisplayName("测试BeanFactoryAware动态加载Bean")
	public void getConnection(){
		// 动态加载Bean
		dynamicBeanLoadService.loadDynamicBean();

		// 获取并且使用动态Bean
		DynamicComponent 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;

	@Override
	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
		this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
	}

	// 自定义方法,用于加载指定目录下的类文件并注册为 Spring Bean
	public 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  -> TUser1
							String 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";
		// 动态加载Bean
		dynamicLoadClass.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.coloradmin.cn/o/1467201.html

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

相关文章

iOS调用系统已安装地图及内置地图实现

info.plist要添加scheme: 1.地图列表: NSArray *mapKeys=[[NSArray alloc] initWithObjects:@"com.autonavi.minimap",@"com.baidu.BaiduMap",@"com.google.android.apps.maps",@"com.tencent.map", nil]; NSArray *mapSchemes=[[NS…

劫持已经存在的DLL

这里找到一个成功加载的 这里先把原来程序正常的dll改名为libEGL1.dll&#xff0c;然后将我们自己的dll改名为libEGL.dll 然后再重新执行程序&#xff0c;这里同样是弹出了窗口

《教育教学论坛》期刊是什么级别?是核心期刊吗?是C刊吗?

​标题解答 问&#xff1a;《教育教学论坛》版面费&#xff1f; 答&#xff1a;VX:JDQJDQ444 问&#xff1a;《教育教学论坛》是核心期刊吗&#xff1f; 答&#xff1a;不是核心期刊 问&#xff1a;《教育教学论坛》是正规期刊吗&#xff1f; 答&#xff1a;是正规期刊 …

vue中使用echarts绘制双Y轴图表时,刻度没有对齐的两种解决方法

文章目录 1、原因2、思路3、解决方法3.1、使用alignTicks解决3.2、结合min和max属性去配置interval属性1、首先固定两边的分隔的段数。2、结合min和max属性去配置interval。 1、原因 刻度在显示时&#xff0c;分割段数不一样&#xff0c;导致左右的刻度线不一致&#xff0c;不…

【Java程序设计】【C00283】基于Springboot的校园志愿者管理系统(有论文)

基于Springboot的校园志愿者管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的校园志愿者管理系统 本系统分为系统功能模块、管理员功能模块以及志愿者功能模块。 系统功能模块&#xff1a;用户进入到系统…

Java的编程之旅27——继承

1.继承的简介 继承是面向对象编程中的一个重要概念&#xff0c;指的是一个类可以继承另一个类的属性和方法。被继承的类称为父类或基类&#xff0c;继承这个父类的类称为子类或派生类。 通过继承&#xff0c;子类可以继承父类的属性和方法&#xff0c;使得子类具有相似的行为…

CSS实现半边边框(只有边框的部分可见)

CSS实现半边边框&#xff08;只有边框的部分可见&#xff09; <div class"part box"><h1>内容</h1><!-- 绘出下面两个对角边框--><div class"part-footer"></div> </div>主要代码 .box {width: 100px;height:…

博睿数据率先发布HarmonyOS NEXT系统的应用异常观测SDK

近日&#xff0c;博睿数据作为业界领先的厂商&#xff0c;凭借对技术的深刻理解和前瞻性视野&#xff0c;率先发布支持HarmonyOS NEXT&#xff08;"纯血鸿蒙"&#xff09;系统的应用异常观测SDK&#xff0c;实现了应用异常的全面回溯。这一突破性技术将引领行业标准&…

为什么前端开发变得越来越复杂了?这可能是我们的错

前端训练营&#xff1a;1v1私教&#xff0c;终身辅导计划&#xff0c;帮你拿到满意的 offer。 已帮助数百位同学拿到了中大厂 offer。欢迎来撩~~~~~~~~ Hello&#xff0c;大家好&#xff0c;我是 Sunday。 最近有很多同学来问我&#xff1a;“Sunday 老师&#xff0c;前端学起…

从 0 开始在项目中引入 Element Plus

此前&#xff0c;已经写文章介绍了如何《从 0 开始创建 Vue 项目》&#xff0c;今天我们来说说&#xff0c;怎么在 Vue 项目中引入 Element Plus。 文章目录 一、简介二、准备三、安装 Element Plus四、快速上手五、自动导入总结 一、简介 Element Plus 是一个基于 Vue 3.0 重…

【实战篇】Redis单线程架构的优势与不足

前言 01 Redis中的多线程02 I/O多线程03 Redis中的多进程问题 04 结论 很多人都遇到过这么一道面试题&#xff1a;Redis是单线程还是多线程&#xff1f;这个问题既简单又复杂。说他简单是因为大多数人都知道Redis是单线程&#xff0c;说复杂是因为这个答案其实并不准确。 难道R…

uniapp腾讯地图JavaScript Api,H5端和原生APP端可用

因项目需要&#xff0c;在uniapp中集成使用腾讯地图&#xff0c;为了方便维护&#xff0c;希望通过一套代码实现H5和APP同时可用。H5显示相对简单&#xff0c;APP端比较麻烦&#xff0c;记录下实现过程 一、集成步骤 1.使用 renderjs script标签使用renderjs&#xff0c;因为…

互联网加竞赛 机器视觉 opencv 深度学习 驾驶人脸疲劳检测系统 -python

文章目录 0 前言1 课题背景2 Dlib人脸识别2.1 简介2.2 Dlib优点2.3 相关代码2.4 人脸数据库2.5 人脸录入加识别效果 3 疲劳检测算法3.1 眼睛检测算法3.2 打哈欠检测算法3.3 点头检测算法 4 PyQt54.1 简介4.2相关界面代码 5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#x…

[yolov9]使用python部署yolov9的onnx模型

【框架地址】 https://github.com/WongKinYiu/yolov9 【yolov9简介】 在目标检测领域&#xff0c;YOLOv9 实现了一代更比一代强&#xff0c;利用新架构和方法让传统卷积在参数利用率方面胜过了深度卷积。 继 2023 年 1 月 正式发布一年多以后&#xff0c;YOLOv9 终于来了&a…

NXP实战笔记(八):S32K3xx基于RTD-SDK在S32DS上配置LCU实现ABZ解码

目录 1、概述 2、SDK配置 2.1、IO配置 2.2、TRGMUX配置 2.3、LCU配置 2.4、Trgmux配置 2.5、Emios配置 2.6、代码实现 1、概述 碰到光电编码器、磁编码器等,有时候传出来的位置信息为ABZ的方式,在S32K3里面通过TRGMUX、LCU、Emios结合的方式可以实现ABZ解码。 官方…

Linux快速修改ip地址

Linux修改IP配置 一 、查找ip配置文件 ifcfg-ens33二、编辑 vi ifcfg-ens33文件三、重启网络或者重启系统 一 、查找ip配置文件 ifcfg-ens33 cd /etc/sysconfig/network-scripts/ls //查看network-scripts文件夹下面的文件二、编辑 vi ifcfg-ens33文件 vi ifcfg-ens33注意&…

初始化(挂载)Linux数据盘(小于2TB)

本文中的操作系统以Linux CentOS 7.5 64位操作系统为例&#xff0c;采用fdisk分区工具为数据盘设置分区。 前提条件 已成功挂载云硬盘。 创建磁盘分区 如果数据盘对外呈现为一个磁盘&#xff0c;不需要分区&#xff0c;可以跳过此步骤。 1.登录Linux实例。 2.运行如下命令&…

Rust核心:【所有权】相关知识点

rust在内存资源管理上采用了&#xff08;先进优秀&#xff1f;算吗&#xff09;但特立独行的设计思路&#xff1a;所有权。这是rust的核心&#xff0c;贯穿在整个rust语言的方方面面&#xff0c;并以此为基点来重新思考和重构软件开发体系。 涉及到的概念点&#xff1a;借用&am…

【Vuforia+Unity】AR05-实物3D模型识别功能实现(ModelTarget )

不管是什么类型的识别Vuforia的步骤基本都是: 把被识别的物体转成图、立体图、柱形图,3D模型、环境模型,然后模型生成Vuforia数据库-导入Unity-参考模型位置开始摆放数字内容,然后参考模型自动隐藏-发布APP-识别生活中实物-数字内容叠加上去! 对于3D物体的识别,可以是虚…

鸿蒙原生应用再添一批新丁!看看新闻、 随申办、浙里办、得物、新零售事业群等入局鸿蒙

鸿蒙原生应用再添一批新丁&#xff01;看看新闻、 随申办、浙里办、得物、新零售事业群等入局鸿蒙 来自 HarmonyOS 微博2月22日消息&#xff0c;#鸿蒙千帆起#上海广播电视台旗下 看看新闻KNEWS 宣布启动鸿蒙原生应用开发&#xff0c;上海广播电视台也成为了全国首家推行鸿蒙原…