spring:实现初始化动态bean|获取对象型数组配置文件

0. 引言

近期因为要完成实现中间件的工具包组件,其中涉及要读取对象型的数组配置文件,并且还要将其加载为bean,因为使用了spring 4.3.25.RELEASE版本,很多springboot的相关特性无法支持,因此特此记录,以方便后续同学有相同情况可以参考

1. 获取对象型数组配置文件

首先对象型数组配置文件如下所示:

minio.clients[0].name=xxx
minio.clients[0].endpoint=http://ip1:9000
minio.clients[0].access.key=admin
minio.clients[0].secret.key=asd
minio.clients[0].default.bucket=wu
minio.clients[1].name=yyy
minio.clients[1].endpoint=http://ip2:9000
minio.clients[1].access.key=admin
minio.clients[1].secret.key=asd
minio.clients[1].default.bucket=wu

转换成yml的格式如下:

minio:clients:- name: xxxendpoint: http://ip1:9000access:key: adminsecret:key: asddefault:bucket: wu- name: yyyendpoint: http://ip2:9000access:key: adminsecret:key: asddefault:bucket: wu

如果是springboot项目,我们直接用一个@ConfigurationProperties(prefix="minio.clients"),然后配置一个实体类就可以实现了,但这里因为遇到的是较老版本的spring项目,不支持该注解。于是尝试用其他方式实现。

@Value形式
首先来看@Value的确能够帮助我们读取到配置项,但是只能针对基础类型或者基础类型数组的配置项,对于我们对象项的数组配置文件,就不支持了,而spring中,除了这种方式,还有可以直接通过操作Environment对象来实现

Environment形式
可以看到通过environment.getProperty方法,是可以获取到我们想要的配置项的,于是这种方式明显是可行的。

同时Environment读取配置项时,要指定配置文件,于是需要借助@PropertySource来声明,同时因为这是一个工具包,也就是说配置文件可能会没有,没有则不用初始化bean,有对应配置文件再自动初始化bean,这是我们想要实现的

点开@PropertySource注解,我们可以看到一个ignoreResourceNotFound属性,从属性名已经告诉我们它的作用了,将其值设置为true,就可以实现配置文件存在时读取配置项,不存在时也不会报错

在这里插入图片描述

完整的示例如下:

@Configuration
@PropertySource(value = {"classpath:applicaiton.properties","classpath:minio.properties"}, ignoreResourceNotFound=true)
public class MinioMultiConfiguration {@Resourceprivate Environment environment;...   
}    

如何动态获取非固定长度数组配置项?
其次我们要观察这里的需求,因为要获取的minio.clients配置实际上是多个,这里我们只是列举了两个,因为实现的是工具包,后续可能还会配置很多个,所以长度是非预期的。

那么我们就需要获取到这个数组的长度,如果是springboot,可以直接通过List<配置实体类> list定义的集合,获取集合长度即可,但是这里spring中,无法直接获取到数组长度,于是为了满足需求,只能采取了一个笨方法,直接定义一个长度配置minio.clients.length=2,后续大家这里有更好的办法可以留言讨论

然后我们就在代码中通过for循环获取配置项即可

2. 如何将bean注册到spring容器

同时因为我这里的需求还需要初始化对应的MinioClient,那就需要将创建的bean,注册到spring容器中,而注册到容器除了@Bean注解的方式,如下所示

@Configuration
public class MinioConfiguration {/*** 对象存储服务的url*/@Value("${minio.endpoint:null}")private String endpoint;/*** 用户ID*/@Value("${minio.access.key:null}")private String accessKey;/*** 账户密码*/@Value("${minio.secret.key:null}")private String secretKey;/*** 默认桶名*/@Value("${minio.default.bucket:null}")private String defaultBucketName = "wu";@Beanpublic MinioClient minioClient() throws Exception{MinioProperties minioProperties = new MinioProperties(endpoint, accessKey, secretKey, defaultBucketName);if(StringUtils.isEmpty(minioProperties.getEndpoint())){return null;}return new MinioClient(minioProperties.getEndpoint(), minioProperties.getAccessKey(), minioProperties.getSecretKey());}
}

还可以通过BeanFactory来进行注册,如下所示

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerSingleton("beanName", new MinioClient());

可以看到我们这里因为要循环读取配置项,bean的个数是不定的,所以固定使用@Bean的形式肯定行不通,只能通过beanFactory进行注册

bean的注册时机
我们知道bean肯定是要在项目启动时就注册的,但是启动时也分了很多阶段,比如我们初始化好的bean实际上是要通过@Autowired@Resource引用的,所以我们肯定需要在这两个引用之前就注册好,否则就会报错bean找不到了。

spring中项目启动时执行方法,有几种方式,比较常用的有@PostConstruct注解的方式,但这种方式的执行顺序是@Bean > @Autowired > @PostConstruct,因此它肯定是不行了

于是我们尝试另一种方式通过申明BeanFactoryPostProcessor接口,实现postProcessBeanFactory方法,这可以对beanFactory进行一些自定义的修改,而我们就可以在这些修改中将bean注册进去

同时因为要通过Environment获取配置项,于是我们还需要申明下EnvironmentAware,通过setEnvironment方法把Environment注册进来,当然你也可以选择通过beanFactory.getBean("environment")获取

完整的示例代码如下:

public class MinioMultiBeanFactoryPostProcessor implements BeanFactoryPostProcessor, EnvironmentAware {private final static Logger log = LogManager.getLogger(MinioMultiBeanFactoryPostProcessor.class);private Environment environment;@Overridepublic void setEnvironment(Environment environment) {this.environment = environment;}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {if(!environment.containsProperty("minio.clients.length")){log.error("未识别到minio.clients.length,取消配置多个minioClient");return;}Integer length = 0;try {length = environment.getProperty("minio.clients.length", Integer.class);}catch (Exception e){throw new RuntimeException("minioClient初始化失败,minio.clients.length数据类型为Int");}for (int i = 0; length != null && i < length; i++) {String name = environment.getProperty("minio.clients["+i+"].name");String endpoint = environment.getProperty("minio.clients["+i+"].endpoint");String access = environment.getProperty("minio.clients["+i+"].access.key");String secret = environment.getProperty("minio.clients["+i+"].secret.key");String bucket = environment.getProperty("minio.clients["+i+"].default.bucket");try{// 自定义对象MinioProperties minioProperties = new MinioProperties(endpoint, access, secret, bucket);// 创建clientMinioClient minioClient = new MinioClient(minioProperties.getEndpoint(), minioProperties.getAccessKey(), minioProperties.getSecretKey());beanFactory.registerSingleton(name+"MinioClient", minioClient);}catch (Exception e){log.error(String.format("minioClient初始化失败:%s", ExceptionUtil.getErrorInfo(e)));}}}
}

然后还需要结合上述说明的@Bean > @Autowired的顺序,因为我们自定义的BeanFactoryPostProcessor现在还只是个单纯的类,我们也需要将其声明为bean才能实现修改BeanFactory的目的,于是通过@Bean来初始化

@Configuration
@PropertySource(value = {"classpath:application.properties","classpath:minio.properties"}, ignoreResourceNotFound=true)
public class MinioMultiConfiguration {@Beanpublic MinioMultiBeanFactoryPostProcessor minioMultiBeanFactoryPostProcessor(){return new MinioMultiBeanFactoryPostProcessor();}}

至此,我们初始化动态bean的操作就完成了,以上方式适用于任何spring项目,对需要搭建中间包的项目更加适用,大家可以选择性参考

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

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

相关文章

Mac配置iTerm样式终端

一、MacOs系统 MacOs中终端使用iTerm2 1. 配置oh-my-zsh oh my zsh 的地址&#xff1a; https//github.com/ohmyzsh/ohmyzsh 插件存放位置&#xff1a;~/.oh-my-zsh/plugins 下载常用的插件 git clone http://github.com/zsh-users/zsh-syntax-highlighting.git 修改配…

怎么将几张图片做成pdf合在一起

怎么将几张图片做成pdf合在一起&#xff1f;在我们平时的工作中&#xff0c;图片和pdf都是非常重要的电脑文件&#xff0c;使用也非常频繁&#xff0c;图片能够更为直观的展示内容&#xff0c;而pdf则更加的正规&#xff0c;很多重要文件大多会做成pdf格式的。在职场人的日常工…

TypeError: res.data.map is not a function微信小程序报错

从数据库查&#xff1a; 调用的是&#xff1a; 访问的springboot后端是这个&#xff1a; 打印出来如下&#xff1a; 看到是json格式的数据 [Users [id3, name刘雨昕, phone18094637788, admintrue, actionsJsonadmin, createAtSat Sep 16 10:11:20 CST 2023, tokentest], User…

深入了解队列数据结构:定义、特性和实际应用

文章目录 &#x1f34b;引言&#x1f34b;队列的定义&#x1f34b;队列的实现&#x1f34b;队列的应用&#x1f34b;练习题&#x1f34b;结语 &#x1f34b;引言 队列&#xff08;Queue&#xff09;是计算机科学中一种重要的数据结构&#xff0c;它常用于各种应用程序中&#x…

拼多多API接口解析,实现根据ID取商品详情

拼多多是一个流行的电商平台&#xff0c;它提供了API接口供开发者使用。要根据ID获取商品详情&#xff0c;您需要使用拼多多API接口并进行相应的请求。 以下是使用拼多多API接口根据ID获取商品详情的示例代码&#xff08;使用Python编写&#xff09;&#xff1a; import requ…

​专业图像处理软件 Photoshop 2023 mac版本更新(ps2023中文)

​Photoshop 2023 mac是一款图像编辑和图形设计软件&#xff0c;广泛应用于专业人士和爱好者。它提供了许多工具和功能&#xff0c;用于创建、编辑和增强数字图像&#xff0c;包括图层、蒙版、滤镜和各种选择工具。Photoshop还支持多种文件格式&#xff0c;包括psD、JPEG、PNG和…

全套办公软件Office 2019 mac专业版功能

Microsoft office 2019 Beta for Mac 是一款办公软件套装&#xff0c;它包含常用的办公应用程序&#xff0c;如 Word、Excel、PowerPoint 和 Outlook 等。office 2019 Beta 版本是一个测试版本&#xff0c;旨在让用户提前体验下一个版本的 office 套件&#xff0c;以便用户可以…

全国职业技能大赛云计算--高职组赛题卷③(私有云)

全国职业技能大赛云计算--高职组赛题卷③&#xff08;私有云&#xff09; 第一场次题目&#xff1a;OpenStack平台部署与运维任务1 基础运维任务&#xff08;5分&#xff09;任务2 OpenStack搭建任务&#xff08;15分&#xff09;任务3 OpenStack云平台运维&#xff08;15分&am…

2023!6招玩转 Appium 自动化测试

Appium是个什么鬼 Appium是一个移动端的自动化框架&#xff0c;可用于测试原生应用&#xff0c;移动网页应用和混合型应用&#xff0c;且是跨平台的。可用于IOS和Android以及firefox的操作系统。原生的应用是指用android或ios的sdk编写的应用&#xff0c;移动网页应用是指网页…

Leetcode198. 打家劫舍

https://leetcode.cn/problems/house-robber/description/ 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷闯入&…

网络初识

一 IP 地址 概念: IP 地址主要用于表示网络主机、其他网络设备&#xff08;如路由器&#xff09;的网络地址。简单说&#xff0c;IP地址用于定位主机的网络地址 格式 IP 地址是一个32为的二进制数&#xff0c;通常被分割为4个“8位二进制数“&#xff08;也就是4个字节&…

layui框架学习(45: 工具集模块)

layui的工具集模块util支持固定条、倒计时等组件&#xff0c;同时提供辅助函数处理时间数据、字符转义、批量事件处理等操作。   util模块中的fixbar函数支持设置固定条&#xff08;2.7版本的帮助文档中叫固定块&#xff09;&#xff0c;是指固定在页面一侧的工具条元素&…

机器学习第五课--广告点击率预测项目以及特征选择的介绍

这个项目的主要的目的是通过给定的广告信息和用户信息来预测一个广告被点击与否。 如果广告有很大概率被点击就展示广告&#xff0c;如果概率低&#xff0c;就不展示。 因为如果广告没有被点击&#xff0c;对双方&#xff08;广告主、平台&#xff09;来讲都没有好处。所以预测…

软件测试/测试开发丨利用人工智能ChatGPT自动生成架构图

点此获取更多相关资料 简介 架构图通过图形化的表达方式&#xff0c;用于呈现系统、软件的结构、组件、关系和交互方式。一个明确的架构图可以更好地辅助业务分析、技术架构分析的工作。架构图的设计是一个有难度的任务&#xff0c;设计者必须要对业务、相关技术栈都非常清晰…

【PLC GX Works2】创建一个工程

PLC GX Works2软件安装 https://www.jcpeixun.com/software/375 程序编写 1、工程中找到新建 2、新建 3、导航栏中选择第三行第一个&#xff0c;是全局软元件注释 4、修改软元件名x0为点动按钮&#xff0c;y1为电机&#xff0c;之后关闭即可。 5、左母线&#xff0c;右…

多输入多输出 | MATLAB实现GA-BP遗传算法优化BP神经网络多输入多输出

多输入多输出 | MATLAB实现GA-BP遗传算法优化BP神经网络多输入多输出 目录 多输入多输出 | MATLAB实现GA-BP遗传算法优化BP神经网络多输入多输出预测效果基本介绍程序设计往期精彩参考资料 预测效果 基本介绍 多输入多输出 | MATLAB实现GA-BP遗传算法优化BP神经网络多输入多输出…

uniapp获取一周日期和星期

UniApp可以使用JavaScript中的Date对象来获取当前日期和星期几。以下是一个示例代码&#xff0c;可以获取当前日期和星期几&#xff0c;并输出在一周内的每天早上和晚上&#xff1a; // 获取当前日期和星期 let date new Date(); let weekdays ["Sunday", "M…

React(react18)中组件通信03——简单使用 Context 深层传递参数

React&#xff08;react18&#xff09;中组件通信03——简单使用 Context 深层传递参数 1. 前言1.1 React中组件通信的其他方式1.2 引出 Context 2. 简单例子3. 语法说明3.1 createContext(defaultValue)3.2 value3.3 useContext(SomeContext) 4. 总结4.1 Context4.1.1 Context…

解决方案| anyRTC远程检修应用场景

背景 在这个科技飞速发展的时代&#xff0c;各行各业都要求高效运转。然而&#xff0c;当出现问题时&#xff0c;我们却常常因为无法及时解决而感到困扰&#xff0c;传统解决问题的方式是邀请技术人员现场解决问题&#xff0c;如果技术人员解决不了&#xff0c;还要邀请专家从…

23年下考前须知-软考中级信息安全工程师

信息安全工程师主要涉及计算机信息安全方面&#xff0c;在计算机软硬件、网络、应用相关领域从事安全系统设计、安全产品开发、产品集成、信息系统安全检测与审计等方面工作&#xff0c;服务单位可以是国家机关、企事业单位及科研教学单位等。 一、考试报名时间 信安考试一年…