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
	 */
	@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 可以在一定程度上提高系统的灵活性和可配置性,但是也需要谨慎考虑和评估其带来的复杂性和性能影响。适合在对灵活性要求较高、定制化程度较高的场景下使用。

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

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

相关文章

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

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

Django定时任务之django_apscheduler使用

Django定时任务之django_apscheduler使用 今天在写一个任务需求时需要用到定时任务来做一部分数据处理与优化&#xff0c;于是在了解完现有方法&#xff0c;结合自己需求决定使用django_apscheduler&#xff0c;记录一下过程&#xff0c;有几篇值得参考的文章放在结尾&#xf…

8.网络游戏逆向分析与漏洞攻防-游戏网络架构逆向分析-游戏底层功能对接类GameProc的实现

内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;通过逆向分析确定游戏明文接收数据过程 码云地址&#xff08;master 分支&#xff09;&#xff1a;https://gitee.com/dye_your_fingers/titan 码云版本号&#xff1a;bcf7559184863febdcad819e48aaa…

应用配置管理

一、Pod 配置管理 可变配置用 ConfigMap&#xff1b; 敏感信息用 Secret&#xff1b; 身份认证用 ServiceAccount 这几个独立的资源来实现的&#xff1b; 资源配置用 Resources&#xff1b; 安全管控用 SecurityContext&#xff1b; 前置校验用 InitContainers 这几个在 …

在VSCode中新配置一个ros项目

如何从零开始配置一个ros项目 预先准备初始化ros工程运行hello_ros进行第一个示例进行编译测试 预先准备 首先要在vscode中安装&#xff08;必须安装的&#xff09;&#xff1a;ros&#xff0c;c&#xff0c;cmake&#xff0c;cmake tools&#xff08;补全camkelist文件&#…

Mcal篇 配置Dio模块输出

1、打开EB&#xff0c;新建工程 AUTOSAR version 4.0.3 2、导入Mcu 、Dio、Port三个模块 发现 verify 选项是灰色&#xff0c;重启EB verify&#xff0c;0 Errors 0 Warnings 验证OK 3、配置 clock 时钟 4、配置Dio 目标是 配置15.0~15.3 四个引脚 输出 改为DioPort_…

第2.5章 StarRocks表设计——行列混存表

注&#xff1a;本篇文章阐述的是StarRocks- 3.2.3版本的行列混存表 一、概述 1.1 背景 StarRocks 基于列存格式引擎构建&#xff0c;在高并发场景&#xff0c;用户希望从系统中获取整行数据。当表宽时&#xff0c;列存格式将放大随机IO和读写。自3.2.3开始&#xff0c;StarRo…

DDS通信协议

DDS&#xff08;Data Distribution Service&#xff09;是一套通信协议和 API 标准&#xff1b;它提供了以数据为中心的连接服务&#xff0c;基于发布者-订阅者模型。这是一套中间件&#xff0c;它提供介于操作系统和应用程序之间的功能&#xff0c;使得组件之间可以互相通信。…

Qt Creator如何快速添加函数说明

/***************************************************************** *函数名称&#xff1a;Name *功能描述&#xff1a;详细描述 *参数说明&#xff1a;参数说明 *返回值&#xff1a; 返回值说明 ******************************************************************/

图像生成评价指标:Inception Score和 FID 的定义,区别,联系。

IS&#xff08;Inception Score&#xff09;和FID&#xff08;Frechet Inception Distance score&#xff09;的定义&#xff0c;区别&#xff0c;联系&#xff1a; IS&#xff08;Inception Score&#xff09; 定义&#xff1a; IS基于Google的预训练网络Inception Net-V3。…

【服务发现--ingress】

1、ingress介绍 Ingress 提供从集群外部到集群内服务的 HTTP 和 HTTPS 路由。 流量路由由 Ingress 资源所定义的规则来控制。 Ingress 是对集群中服务的外部访问进行管理的 API 对象&#xff0c;典型的访问方式是 HTTP。 Ingress 可以提供负载均衡、SSL 终结和基于名称的虚拟…

贪心算法---前端问题

1、贪心算法—只关注于当前阶段的局部最优解,希望通过一系列的局部最优解来推出全局最优----但是有的时候每个阶段的局部最优之和并不是全局最优 例如假设你需要找给客户 n 元钱的零钱&#xff0c;而你手上只有若干种面额的硬币&#xff0c;如 1 元、5 元、10 元、50 元和 100…

【变压器故障诊断分类及预测】基于GRNN神经网络

课题名称&#xff1a;基于GRNN神经网络的变压器故障诊断分类及预测 版本日期&#xff1a;2024-02-10 运行方式&#xff1a;直接运行GRNN0507.m文件 代码获取方式&#xff1a;私信博主或QQ&#xff1a;491052175 模型描述&#xff1a; 对变压器油中溶解气体进行分析是变压器…

JavaAPI常用类01

目录 概述 Object类 Object类_toString() 代码展示 重写toString()方法前后输出 Object类_equals() 代码展示 重写equals()方法前后输出对比 Arrays类 equals()方法 Binary Search&#xff08;二分查找&#xff09; copyOf()方法 sort()方法 了解sort()方法 进阶…

在使用nginx的时候快速测试配置文件,并重新启动

小技巧 Nginx修改配置文件后需要重新启动&#xff0c;常规操作是启动在任务管理器中关闭程序然后再次双击nginx.exe启动&#xff0c;但是使用命令行就可以快速的完成操作。 将cmd路径切换到nginx的安装路径 修改完成配置文件后 使用 nginx -t校验nginx 的配置文件是否出错 …

Python入门必学:reverse()和reversed()的区别

Python入门必学&#xff1a;reverse()和reversed()的区别 &#x1f4c5;2024年02月25日 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程…

Cover和contain属性

一.背景的盒子 代码&#xff1a; <body><div class"box"></div><style>.box {width: 500px;height: 500px;border: 1px solid #ccc;background: url(./20191017095131790.png) no-repeat;}</style></body> 盒子的宽度和高度是…

SpringBootRest服务调用

目录 RestTemplate 依赖配置 自定义RestTemplate webCilent 依赖配置 自定义webCilent springboot中有两种方式实现Rest远程服务调用&#xff0c;分别是RestTemplate与webCilent。下面分别介绍一下这两种方式。 RestTemplate 依赖配置 RestTemplate是Spring Framework提供的…

不会做UI自动化测试?一起设计框架再实践吧

目的 相信做过测试的同学都听说过自动化测试&#xff0c;而UI自动化无论何时对测试来说都是比较吸引人的存在。 相较于接口自动化来说它可以最大程度的模拟真实用户的日常操作与特定业务场景的模拟&#xff0c;那么存在即合理&#xff0c;自动化UI测试自然也是广大测试同学职…

2.23日学习打卡----初学Nginx(二)

2.23日学习打卡 目录: 2.23日学习打卡一. Nginx 虚拟主机虚拟主机的分类Nginx支持三种类型的虚拟主机配置Nginx虚拟主机单网卡多IP配置Nginx虚拟主机_基于域名虚拟主机配置Nginx虚拟主机基于多端口的配置4 二. Nginx 核心指令root和alias指令的区别return指令rewrite指令rewrit…