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.xdnf.cn/news/139637.html

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

相关文章

Springboot2 Pandas Pyecharts 量子科技专利课程设计大作业

数据集介绍 1.背景 根据《中国科学&#xff1a;信息科学》期刊上的一篇文章&#xff0c;量子通信包括多种协议与应用类型&#xff1a; 基于量子隐形传态与量子存储中继等技术&#xff0c;可实现量子态信息传输&#xff0c;进而构建量子信息网络&#xff0c;已成为当前科研热点&…

HTTP参数类型中的Query和Body参数

在接口中常见到query参数和body参数&#xff0c;那么它对应的传参方式是&#xff1f; ★ query查询参数 ---> params ---> route.params.参数 ★ body请求体参数 ---> data ---> route.query.参数 总结&#xff1a; GET请求只能传Query参数&#xff0c; POST请…

网络编程day05(IO多路复用)

今日任务&#xff1a; TCP多路复用的客户端、服务端&#xff1a; 服务端代码&#xff1a; #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <unistd.h> …

【动态规划刷题 17】回文子串 最长回文子串

647. 回文子串 链接: 647. 回文子串 给你一个字符串 s &#xff0c;请你统计并返回这个字符串中 回文子串 的数目。 回文字符串 是正着读和倒过来读一样的字符串。 子字符串 是字符串中的由连续字符组成的一个序列。 具有不同开始位置或结束位置的子串&#xff0c;即使是由…

2023华为杯研究生数学建模F题思路分析

更多思路代码查看文末名片 1.如何有效应用双偏振变量改进强对流预报&#xff0c;仍是目前气象预报的重点难点问题。请利用题目提供的数据&#xff0c;建立可提取用于强对流临近预报双偏振雷达资料中微物理特征信息的数学模型。临近预报的输入为前面一小时&#xff08;10帧&…

不再跳票Fedora 26 正式发布!

经过延期和跳票&#xff0c;Fedora 26终于和大家见面了&#xff0c;下面是Fedora 项目负责人Matthew Miller感谢信 大家好&#xff0c;我很高兴地宣布&#xff0c;从即刻起 Fedora 26 正式可用了。你可以从下面了解到具体信息&#xff0c;也可以马上开始下载&#xff1a; •下载…

CentOS在应用程序菜单中创建快捷方式

背景&#xff1a; 在CentOS系统中&#xff0c;安装一些应用软件的时候&#xff0c;我们可能会自定义安装路径&#xff1b;这样在安装完应用程序后&#xff0c;在“Application”下&#xff0c;可能找不到对应的快捷键&#xff1b;这是就需要手动去创建跨界方式。 应用&#xf…

stm32之GPIO库函数点灯分析

stm32官方为了方便开发者&#xff0c;利用CubeMX 生成HAL库有关的C代码。HAL库就是硬件抽象层(hardware abstraction layer)&#xff0c;生成一系列的函数帮助我们快速生成工程&#xff0c;脱离复杂的寄存器配置。stm32相对于51来功能强大&#xff0c;但是寄存器的数量也不是一…

MySQL备份及恢复

目录 MySQL备份 MySQL备份方法 备份策略 mysql的完全备份 mysql的增量备份 MySQL恢复 mysql完全恢复 mysql增量备份的恢复 MySQL备份 MySQL备份是基于对MySQL的日志进行备份&#xff0c;且恢复也是通过日志进行数据恢复。 MySQL备份方法 物理备份&#xff1a;直接对…

北京智和信通亮相2023IT运维大会,共话数智浪潮下自动化运维新生态

2023年9月21日&#xff0c;由IT运维网、《网络安全和信息化》杂志社联合主办的“2023&#xff08;第十四届&#xff09;IT运维大会”在北京成功举办。大会以“以数为基 智引未来”为主题&#xff0c;北京智和信通技术有限公司&#xff08;下文简称&#xff1a;北京智和信通&…

爱看小说手机网源码全站带数据带自动采集程序/ThinkPHP内核小说网站源码+书库数据库带自动采集

爱看小说手机网源码全站带数据带自动采集程序&#xff0c;爱看小说程序源码2W条数据全站打包,自动采集程序网站源码,后台已经更新5个采集规则可以采集小说30万本大概约10G。 分享的这一款自带2w数据爱看小说网源码全站带数据打包,ThinkPHP内核小说网站源码带听书等全部插件&am…

TouchGFX之画布控件

TouchGFX的画布控件&#xff0c;在使用相对较小的存储空间的同时保持高性能&#xff0c;可提供平滑、抗锯齿效果良好的几何图形绘制。 TouchGFX 设计器中可用的画布控件&#xff1a; LineCircleShapeLine Progress圆形进度条 存储空间分配和使用​ 为了生成反锯齿效果良好的…

矩阵论—凯莱-哈密顿定理

凯莱-哈密顿定理内容 凯莱-哈密顿定理典型例题 典型例题 我们先来观察这个题目&#xff0c;题目要求&#xff0c;若直接将矩阵A 代入计算&#xff0c;则会非常复杂&#xff0c;因此&#xff0c;这条路是走不通的。 我们试着引入我们今天介绍的凯莱-哈密顿定理来解这个…

Linux,计算机网络,数据库

Linux&#xff0c;计算机网络&#xff0c;数据库&#xff0c;操作系统 一、Linux1、linux查看进程2、linux基本命令3、top命令、查看磁盘 二、计算机网络1、HTTP的报文段请求 Repuest响应 Response 2、HTTP用的什么连接3、TCP的三次握手与四次挥手三次握手四次挥手 4、在浏览器…

【MATLAB第76期】基于MATLAB的代表性样本筛选方法合集(针对多输入单输出数据)

【MATLAB第76期】基于MATLAB的代表性样本筛选方法合集&#xff08;针对多输入单输出数据&#xff09; 前有筛选变量方法&#xff0c;如局部敏感性分析和全局敏感性分析方法介绍 。 今天提出另外一种思路&#xff0c;去对样本进行筛选。 使用场景&#xff1a; 场景1&#xff1a…

Python 实现 PDF 文件转换为图片 / PaddleOCR

文章用于学习记录 文章目录 前言一、PDF 文件转换为图片二、OCR 图片文字识别提取三、服务器端下载运行 PaddleOCR四、下载权重文件总结 前言 文字识别&#xff08;Optical Character Recognition&#xff0c;简称OCR&#xff09;是指将图片、扫描件或PDF、OFD文档中的打印字符…

Mybatis工作流程及原理详解

一、概述 1.何为mybatis&#xff1f; MyBatis 是一款优秀的持久层框架&#xff0c;它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息&#xff0c;将接口和 J…

数据仓库数据库

在当今的数字化时代&#xff0c;数据存储和管理是非常重要的领域。数据仓库和数据库是两个重要的数据存储和管理工具&#xff0c;它们有着不同的特点和用途。 一、数据仓库与数据库的定义 1. 数据仓库 数据仓库&#xff0c;是为企业所有级别的决策制定过程&#xff0c;提供所…

报错处理:Error: Redis server is running but Redis CLI cannot connect

嗨&#xff0c;读者朋友们&#xff01;今天我来跟大家分享一个我在运维过程中遇到的一个关于Linux上运行Redis服务时的报错及解决方法。 报错信息如下&#xff1a; Error: Redis server is running but Redis CLI cannot connect 这个报错信息表明Redis服务器已经运行&#xff…

达梦数据库-DW-国产化--九五小庞

武汉达梦数据库股份有限公司成立于2000年&#xff0c;是国内领先的数据库产品开发服务商&#xff0c;国内数据库基础软件产业发展的关键推动者。公司为客户提供各类数据库软件及集群软件、云计算与大数据等一系列数据库产品及相关技术服务&#xff0c;致力于成为国际顶尖的全栈…