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

news2024/11/19 13:31:13

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: xxx
      endpoint: http://ip1:9000
      access:
        key: admin
      secret:
        key: asd
      default:
        bucket: wu
    - name: yyy
      endpoint: http://ip2:9000
        access:
          key: admin
        secret:
          key: asd
        default:
          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 {
 
    @Resource
    private 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";

    @Bean
    public 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;

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public 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);
                // 创建client
                MinioClient 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 {

    @Bean
    public MinioMultiBeanFactoryPostProcessor minioMultiBeanFactoryPostProcessor(){
        return new MinioMultiBeanFactoryPostProcessor();
    }

}

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

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

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

相关文章

阿里云服务器u1和经济型e实例有什么区别?

阿里云服务器经济型e实例和云服务器u1有什么区别&#xff1f;同CPU内存配置下云服务器u1性能更强&#xff0c;u1实例价格也要更贵一些。经济型e实例属于共享型云服务器&#xff0c;不同实例vCPU会争抢物理CPU资源&#xff0c;并导致高负载时计算性能波动不稳定&#xff0c;而云…

实时更新进度条:JavaScript中的定时器和异步编程技巧

前言 在Web开发中&#xff0c;有许多场景需要实时地更新页面上的进度&#xff0c;例如上传文件、数据处理等。本文将介绍如何利用JavaScript中的定时器和异步编程技巧来实现实时更新进度&#xff0c;并探讨一些其他解决方案。 处理进度实时更新&#xff1a; 利用异步编程实现实…

可转债长期持有策略——收益与风险、利息收入、案例研究

可转债投资策略——长期持有策略 一、收益与风险的权衡 长期持有可转债是一种投资策略&#xff0c;旨在实现稳定的收益&#xff0c;并在投资期限内从可转债中获得利益。在采用这种策略时&#xff0c;投资者需要平衡可转债的收益和风险&#xff0c;以满足其财务目标。以下是关…

尝试访问启动磁盘设置时出错怎么办?

当出现“尝试访问启动磁盘设置时出错”这样的错误提示&#xff0c;而且启动转换控制面板打不开了时&#xff0c;是无法开启触摸板功能的。我们可以使用以下方法来解决问题。 1. 在Windows桌面左下角搜索框输入“计算机管理”后点击“打开”。 2. 点击“本地用户与组”&#xff…

树结构数据在table中回显 treeselect disabled

<el-table-column label"产业认定" align"center" prop"industryIdentification"><template slot-scope"scope"><treeselectv-if"scope.row.industryIdentification"v-model"scope.row.industryIdentif…

Zookeeper系统模型_客户端命令行

创建 创建ZK节点 语法结构&#xff1a; create [-s] [-e] path data acl 参数&#xff1a; -s&#xff1a;顺序节点-e&#xff1a;临时节点 默认情况下&#xff0c;不添加-s或者-e参数的&#xff0c;创建的是持久节点。 示例&#xff1a; [zk: localhost:2181(CONNECTED) …

Spring Cloud Alibaba Gateway全局token过滤、局部过滤访问时间超过50ms日志提示

文章目录 Spring Cloud Alibaba Gateway验证token在前篇的基础上加入依赖在filter包中创建tokenFilter Spring Cloud Alibaba Gateway局部过滤1.继承AbstractGatewayFilterFactory2.仿照AddRequestHeaderGatewayFilterFactory Spring Cloud Alibaba Gateway验证token 基础搭建…

linux上gitlab备份与还原

三 Gitlab备份 1.gitlab安装 1.1 添加镜像地址 添加镜像地址的目的是为了提高国内用户软件下载的速度&#xff0c;编辑(新建)文件gitlab-ce.repo&#xff0c;指令&#xff1a; vi /etc/yum.repos.d/gitlab-ce.repo复制 输入&#xff1a; [gitlab-ce] namegitlab-ce # 清华…

基于SSM+Vue的亿互游在线平台的设计与开发

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

LeetCode01

LeetCode01 两数之和 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和 为目标值 target 的那两个整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现。 你…

Unity制作射击游戏案例01

整理逻辑思路&#xff1a; //【业务逻辑】这个脚本用来1.控制物体移动旋转&#xff08;WASD&#xff09;、 2.发射子弹&#xff08;空格键&#xff09; //【程序逻辑2】 首先检测用户没有按下空格键 2.如果按下呢执行发射子弹函数 3.克隆子弹 4.让克隆的子弹往前跑 搭…

Seata 基于改良版雪花算法的分布式 UUID 生成器分析

一般来说&#xff0c;除了“全局唯一”这个基本属性之外&#xff0c;还会要求生成出来的 ID 具有“递增趋势”&#xff0c;这样的好处是能减少 MySQL 数据页分裂的情况&#xff0c;从而减少数据库的 IO 压力&#xff0c;提升服务的性能。 雪花算法&#xff0c;就是一个能生产全…

浅谈霍尔电流传感器在汽车电池管理系统中的应用

摘要&#xff1a; 随着电动汽车和混合动力汽车的需求和产量正在增加&#xff0c;两种类型的车辆都需要高电流容量的电池来运行50kW 或更高功率的电机&#xff0c;并且这些都使用高压系统。汽车电池管理系统中对于电流的测量检测需要隔离测量的方式&#xff0c;而霍尔电流传感器…

【DLL修复工具下载】一键修复电脑丢失d3dcompiler_47.dll问题方法

在我们使用电脑的过程中&#xff0c;有时候会遇到一些错误提示&#xff0c;其中“缺失 d3dcompiler_47.dll”就是比较常见的一种。那么&#xff0c;d3dcompiler_47.dll 到底是什么呢&#xff1f;为什么会出现缺失的情况&#xff1f;丢失 d3dcompiler_47.dll 又会对电脑产生什么…

电压放大器如何选型号和参数配置

选择适合的电压放大器型号和配置参数是设计电子系统中至关重要的一步。电压放大器是一种关键的电子器件&#xff0c;用于将输入电压信号放大到所需的输出电压级别。下面西安安泰将详细介绍如何选择电压放大器的型号和配置参数。 确定应用需求&#xff1a;首先&#xff0c;需要明…

MyBatis 日志模块

文章目录 前言LogLogFactory日志应用JDBC 日志BaseJdbcLoggerConnectionLogger应用实现 总结 前言 日志在我们开发过程中占据了一个非常重要的地位&#xff0c;是开发和运维管理之间的桥梁&#xff0c;在Java中的日志框架也非常多&#xff0c;Log4j、Log4j2、slf4j等&#xff…

孙宇晨:稳定币支付交易具百倍增长潜力 后FTX时代行业仍需修炼内功

9月14日,波场TRON创始人、火币HTX全球顾问委员会成员孙宇晨受邀出席于新加坡举办的TOKEN 2049,并参加了“生态系统和行业增长:展望加密货币的未来十年”主题板块的讨论。孙宇晨在发言中表示,接下来的 10 年里,加密货币和区块链的最大日常应用场景仍然是稳定币支付交易,预计将有…

nodeJs+Mongodb+mongoose入门

nodeJsexpressMongodbmongooseNavicat 自我记录 一、简介 1.1 Mongodb 是什么 MongoDB 是一个基于分布式文件存储的数据库&#xff0c;官方地址 https://www.mongodb.com/ 1.2 数据库是什么 数据库&#xff08;DataBase&#xff09;是按照数据结构来组织、存储和管理数据…

KF32A学习笔记(一):工程导入、编译烧录方法(KF32 IDE+ KF32 PRO)

目录 概述KF32 IDE打开现有项目工程1.工程导入2.编译工程3.下载程序 KF32 PRO 概述 本文主要是对KF32A150芯片程序的编译、烧录方法进行说明。针对开发过程中的编译烧录和无代码情况下的烧录两种场景&#xff0c;需要安装ChipON PRO KF32和ChipON IDE KF32两个上位机工具&…

Linux Qt5.15.2 编译QWebEngine源码支持音视频H264

背景 默认自带的QWebEngine 因版权问题不支持音视频功能&#xff0c;需要自己编译源码以支持。 平台&#xff1a;Linux&#xff08;UOS V20 1050&#xff09; Qt&#xff1a;5.15.2 准备工作 下载 Qt 5.15.2 对应版本源码&#xff0c;使用镜像网站或者Qt Maintenance Tool工…