SpringBoot统一属性配置,以数据库作为配置中心

👉 这是一个或许对你有用的社群

🐱 一对一交流/面试小册/简历优化/求职解惑,欢迎加入「芋道快速开发平台」知识星球。下面是星球提供的部分资料: 

31ed71b66530e9f2261f204e041d672d.gif

👉这是一个或许对你有用的开源项目

国产 Star 破 10w+ 的开源项目,前端包括管理后台 + 微信小程序,后端支持单体和微服务架构。

功能涵盖 RBAC 权限、SaaS 多租户、数据权限、商城、支付、工作流、大屏报表、微信公众号等等功能:

  • Boot 仓库:https://gitee.com/zhijiantianya/ruoyi-vue-pro

  • Cloud 仓库:https://gitee.com/zhijiantianya/yudao-cloud

  • 视频教程:https://doc.iocoder.cn

【国内首批】支持 JDK 21 + SpringBoot 3.2.2、JDK 8 + Spring Boot 2.7.18 双版本 

来源:juejin.cn/post/
7332708703400312873


引言

最近工作中常常感到后端 SpringBoot 项目里的属性配置十分混乱,在 SpringBoot 属性配置文件,数据库表,以及各个类中的属性字段都存在。因此,为了统一 SpringBoot 属性配置,尝试着以数据库作为统一的配置中心。

本文将从框架中属性配置存在的问题出发,分析并设计数据库表,之后改造属性的数据注入方式,最后在项目运行中完成验证可行性。

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro

  • 视频教程:https://doc.iocoder.cn/video/

杂乱的属性配置

由于后台系统框架在设计之初没有对属性配置这一块做好统一规范,导致不同的人在着手不同业务的时候都用了各异的实现方式。随着涉及的业务越来越多,框架中属性配置这一块的问题也开始令人头大,配置臃肿的问题也终于到了该解决的时候。

首先概览一下目前 SpringBoot 项目中属性配置的存在情况,大致有三种形式:SpringBoot 属性配置文件数据库配置表以及硬编码属性字段

SpringBoot 属性配置文件

这类属性是配置在 SpringBoot 属性配置文件中的,部分配置还是十分敏感的数据,而且明文编写。

> 基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
>
> * 项目地址:<https://github.com/YunaiV/yudao-cloud>
> * 视频教程:<https://doc.iocoder.cn/video/>

# 阿里云
aliyun.accessKeyId=LT***uao
aliyun.accessKeySecret=0Qhe***byr1f
数据库配置表

这类属性是读取数据库数据,之后加载到缓存或直接使用的。

5d85668707375f93098c4268b0d4e7b4.jpeg

硬编码属性字段

这类属性就是硬编码的常量,同样存在许多敏感数据。

public class WechatConfig {

    public static final class MINI {
        public static final String APP_ID = "wx2***dd5";
        public static final String APP_SECRET = "38f***9c74";
    }
}

配置分离方案

配置分离就是将属性配置与项目工程代码分开,这样不仅可以提高程序的健壮性和可维护性,还能使得属性配置更容易管理,做到不修改代码或重启程序的情况下进行配置更改。

当然,并不是所有的属性配置都需要配置分离,还需要先将它们归类再进一步分析。

属性配置归类

首先分析框架与项目中使用的配置项,并规范为三类:

  • 第一种是 Spring 配置,比如Spring的server.prot,Mybatis的mybatis.mapper-locations,即属于框架层面的,这种规定要配置在application[-ENV].properties

  • 第二种是服务配置,比如定义的日志配置logback-spring.xml及配置logging.path,规定按原本方式单独配置;

  • 最后是第三方平台配置,比如阿里云OSS、微信小程序,规定使用数据库作为配置中心。

第一和第二种配置方式基本无需改动,因此不考虑对其实现配置分离;本次着重于第三方平台相关的配置,并统一以数据库作为配置中心。

数据表设计

在数据库表的设计中,一个属性配置最少由两个字段组成,也就是构成键值对的字段;同时我们可以设计一个分组字段,便于数据的分类和检索;最后,考虑到项目之后的扩展,可以考虑设计一个命名空间字段,用于配置环境区分等。

  • 字段data_keydata_value作为单项配置的键值对,其含义等同于Spring中的properties;

  • 字段data_group作为配置项的分组,例如对阿里云 OSS 的组名为aliyun.oss

  • 字段namespace为命令空间的含义,可以作为区分环境用,或者分租户。

数据表结构如下:

CREATE TABLE `admin_data_config` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增Id',
  `create_time` bigint(20) DEFAULT '0' COMMENT '创建时间',
  `create_user` bigint(20) DEFAULT '0' COMMENT '创建者',
  `update_time` bigint(20) DEFAULT '0' COMMENT '更新时间',
  `update_user` bigint(20) DEFAULT '0' COMMENT '更新者',
  `is_del` tinyint(4) DEFAULT '0' COMMENT '是否删除:1.是 0.否',
  `data_key` varchar(100) DEFAULT '' COMMENT '键',
  `data_value` varchar(100) DEFAULT '' COMMENT '值',
  `description` varchar(50) DEFAULT '' COMMENT '描述',
  `data_group` varchar(50) DEFAULT 'default_group' COMMENT '分组',
  `namespace` varchar(50) DEFAULT 'public' COMMENT '命名空间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT='配置中心';

配置中心表数据示例:

63d30d87fd5395edf90d42d68768ce83.jpeg

编码实现

核心配置类

核心配置类中使用@PostConstruct注解的init读取数据库数据配置,将读取到的数据配置作为MapPropertySource类型的数据源,之后将MapPropertySource放置到MutablePropertySources首位 (addFirst),作为最高优先级配置。

@Configuration
public class DBPropertyDataConfig {

    @Resource
    private ConfigurableEnvironment configurableEnvironment;

    @Resource
    private AdminDataConfigMapper adminDataConfigMapper;

    @PostConstruct
    public void init() {

        MutablePropertySources mutablePropertySources = configurableEnvironment.getPropertySources();
        List<AdminDataConfig> dataConfigList = adminDataConfigMapper.list(null);
        if (dataConfigList == null || dataConfigList.size() == 0) {
            return;
        }
        Map<String, Object> propertyMap = dataConfigList.stream()
                .collect(Collectors.toMap(AdminDataConfig::getDataKey, AdminDataConfig::getDataValue));
        MapPropertySource mapPropertySource = new MapPropertySource("db_data_config", propertyMap);
        mutablePropertySources.addFirst(mapPropertySource);

    }
}
数据注入

在应用新的数据库属性配置前还需要对原先的配置类改造,将字段或setter方法添加@Value注解使配置注入;同样地,对于新的属性配置则需要编写新的配置类。

以前面举例的WechatConfig配置类为例进行改造:

@Configuration
public class WechatConfig {

    public static final class MINI {
        public static String APP_ID;
        public static String APP_SECRET;
    }
    
    @Value("${wechat.mini.app-id}")
    public void setAppId(String appId) {
        MINI.APP_ID = appId;
    }
    @Value("${wechat.mini.app-secret}")
    public void setAppSecret(String appSecret) {
        MINI.APP_SECRET = appSecret;
    }
}
注意事项

配置类的注意事项:

  • 成员变量不可使用final声明

  • 使用Congfiguration将类作为Spring Bean

  • static声明的变量注入需要在setter方法上注解

  • 不能在内部类执行注入

关于Spring Bean的加载顺序的说明:

根据Spring Bean的加载顺序,要保证被注入Bean之前已加载DBPropertyDataConfig;例如,BlackBoxFacade会先于DBPropertyDataConfig加载,则需要@DependsOn指定其依赖关系。如下:

@Service
@DependsOn("DBPropertyDataConfig")
public class BlackBoxFacade {
    @Value("${black-box.company}")
    public String SYS_COMPANY;
}

测试验证

数据准备

准备数据库数据:

INSERT INTO `admin_data_config`
(`data_key`, `data_value`, `description`, `data_group`, `namespace`)
VALUES
('wechat.mini.app-id', 'wx2***', '微信小程序 appid', 'wechat.mini', 'public'),
('wechat.mini.app-secret', '38f***', '微信小程序 app secret', 'wechat.mini', 'public');
接口测试
  • 请求URL:http://localhost:8080/app/account/login

  • 请求方法:POST

  • Content-Type:form-data

  • 请求参数:data : {"jsCode":"FFF"}

断点观测

源代码设置断点:

0c1245f7d19059917f4ed6b58728663c.jpeg

断点数据观测:

22b5ab385325757fada085880231cc04.jpeg

总结与扩展

至此,以数据库作为配置中心的实现就已完成了。这个过程中整个的代码量其实只有核心的数据库配置读取这一点,更多的工作量还是在配置类的改造上。在测试验证通过之后,这个方案已逐渐应用在了线上的所有项目。

当然,以数据库作为配置中心只是一个选择,nacos同样也是一个成熟的可用方案,相比较来说,以数据库作为配置中心无需引入第三方也无需运行新服务,比较适合小型的项目。

最后,以数据库作为配置中心只是统一属性配置改造中的一小环,后面将会继续探索如何动态刷新属性配置,让整个属性配置更加灵活方便。


欢迎加入我的知识星球,全面提升技术能力。

👉 加入方式,长按”或“扫描”下方二维码噢

7e5d3a7b7a24c612bb5df16709ca873d.png

星球的内容包括:项目实战、面试招聘、源码解析、学习路线。

24eb5d3dbf34135c14925ebd0bfa3f8e.png

535794388a572239e244dbc89615b439.png08094fc9fff718ac7604cd747d6acd71.png56cbd020475f957afabf04bfe55d158a.pngdff4cc6f75bf0ba5929ec13be00bfb52.png

文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值