Spring配置参数详解


铿然架构 | 作者 / 铿然一叶 这是 铿然架构 的第 118 篇原创文章


1. 介绍

在应用系统中通常都需要通过获取配置参数来增加灵活性,例如数据库的用户名和密码、连接池配置,ssl配置等等。

配置参数有多种配置方式,如通过开源软件Nacos、Apollo配置,在K8S中通过Configmap或Secret配置,而Spring也提供了自身的参数配置和获取能力,本文将介绍Spring的配置参数能力和使用方式。

2. Spring配置参数

2.1 能力

● 参数来源:配置文件和环境变量。

● 文件格式:yml和properties文件。

● 参数类型:单值,数组,List,Map。

2.2 相关注解

Spring配置参数要使用注解,涉及注解如下:

注解 描述
PropertySource 用于指定配置参数来源文件,依赖Configuration注解才会生效。
Value 指定配置参数名或环境变量名,依赖Component注解才会生效。
ConfigurationProperties 指定配置参数获取时配置节点的起始位置,依赖Component注解才会生效。

注:因为Configuration注解包含了Component注解,因此Value和ConfigurationProperties注解依赖Configuration注解也一样有效。

2.3 配置例子

2.3.1 指定配置文件

如果不指定配置文件,默认从application.yml和application.properties中获取。

2.3.1.1 properties文件

java 复制代码
@Configuration
@PropertySource(value = "classpath:cluster.properties")
public class PropertiesConfiguration {
}

文件路径可以是classpath或绝对路径,绝对路径例子:

java 复制代码
"file:/home/app/cluster.properties"

2.3.1.2 yml文件

PropertySource注解默认不支持解析yaml文件,需要自定义一个工厂类来解析。

java 复制代码
@Configuration
@PropertySource(value = "classpath:cluster.yml", factory = YAMLPropertySourceFactory.class)
public class YAMLConfiguration {
}

工厂类代码:

java 复制代码
public class YAMLPropertySourceFactory implements PropertySourceFactory {
    public org.springframework.core.env.PropertySource<?> createPropertySource(String name, EncodedResource encodedResource) {
        YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
        factory.setResources(encodedResource.getResource());

        Properties properties = factory.getObject();
        return name != null ? new PropertiesPropertySource(name, properties) :
                new PropertiesPropertySource(encodedResource.getResource().getFilename(),properties);
    }
}

2.3.2 指定配置节点起始位置

如下代码:

java 复制代码
@Component
@ConfigurationProperties(prefix = "db")
public class DBMapParam {

表示从db节点之后,即connectInfo开始读取配置参数:

java 复制代码
db:
  connectInfo:
    user: kengcoder
    password:  XDIxde!322332ec

如果配置为:

java 复制代码
@ConfigurationProperties(prefix = "db.connectInfo")

则从user开始读取。

2.3.3 Value注解配置方式

Value注解可以从文件或环境变量获取参数,支持单值,数组,List,Map。

代码:

java 复制代码
@Component
public class AppValueAndEnvParam {

    // 获取单值参数
    @Value("${app.name}")
    private String name;

    // 单值参数设置默认值,如果没有配置则取默认值
    @Value("${app.id:000}")
    private String defaultAppId;

    // 获取环境变量,如果配置和环境变量都有,优先取环境变量
    @Value("${JAVA_HOME}")
    private String javaHome;

    // 获取数组配置
    @Value("${app.whitelistIps}")
    private String[] whitelistIps;

    // 获取列表配置
    @Value("${app.whitelistIps}")
    private List<String> whitelistIpList;

    // 获取map配置
    @Value("#{${db.connectInfoForValue}}")
    private Map<String, String> dbConnectInfo;

    // 获取所有环境变量
    @Value("#{systemProperties}")
    private Map<String, String> systemPropertiesMap;
}

配置:

java 复制代码
app:
  name: myapp
  whitelistIps: 10.192.8.3,10.192.8.4,10.192.8.5
  
db:
  connectInfoForValue: '{"user": "kengcoder", "password": "XDIxde!322332ec", "url": "jdbc:mysql://10.9."}'

输出:

java 复制代码
(name=myapp, defaultAppId=000, javaHome=C:\Program Files\Java, whitelistIps=[10.192.8.3, 10.192.8.4, 10.192.8.5], whitelistIpList=[10.192.8.3, 10.192.8.4, 10.192.8.5], dbConnectInfo={user=kengcoder, password=XDIxde!322332ec, url=jdbc:mysql://10.9.})

2.3.4 Bean配置方式

Bean配置方式从配置文件获取参数,支持单值,数组,List,Map。

通过Bean方式配置,通常要指定配置参数起始节点。

2.3.4.1 复杂Bean

这里演示一个嵌套Bean配置,包括单值,数组和List参数。相关类如下:

代码:

java 复制代码
@Component
@ConfigurationProperties(prefix = "app")
public class ClusterObjectParam {
    private String name;
    private Cluster cluster;
}

@Data
@ToString
public class Cluster {
    private String id;
    private String name;
    private List<Node> nodes;
}

@Data
@ToString
public class Node {
    private String nodeId;
    private String nodeType;
    private Service[] services;
}

@Data
@ToString
public class Service {
    private String name;
    private int port;
}

配置:

java 复制代码
app:
  name: myapp
  cluster:
    id: c-101
    name: my-cluster
    nodes:
      - nodeId: n-101
        nodeType: app
        services:
          - name: account
            port: 8001
          - name: customer
            port: 8002
      - nodeId: n-102
        nodeType: db

输出:

java 复制代码
name: myapp
Cluster(id=c-101, name=my-cluster, nodes=[Node(nodeId=n-101, nodeType=app, services=[Service(name=account, port=8001), Service(name=customer, port=8002)]), Node(nodeId=n-102, nodeType=db, services=null)])

2.3.4.2 Map

代码:

java 复制代码
@Component
@ConfigurationProperties(prefix = "db")
public class DBMapParam {
    private Map<String, String> connectInfo;
}

配置:

java 复制代码
db:
  connectInfo: 
    user: kengcoder
    password:  XDIxde!322332ec
    url: "jdbc:mysql://10.9.2.7:3306/accountdb"

输出:

java 复制代码
{password=XDIxde!322332ec, url=jdbc:mysql://10.9.2.7:3306/accountdb, user=kengcoder}

2.3.5 两种配置方式比较

● 便利性

对于对象参数,Bean配置方式比较简单,只需要对象属性名和参数名一致,同时指定配置起点则可。

Value注解则需要一个个的指定配置参数名。

● 能力

两者都支持单值、数组、List、Map参数,Value支持从文件和环境变量获取参数,而Been配置方式只支持从文件获取参数。

● Map配置格式差异

两者Map参数的配置格式不同,配置不对会解析错误。

Value注解配置方式,必须是json格式的键值对:

java 复制代码
db:
  connectInfoForValue: '{"user": "kengcoder", "password": "XDIxde!322332ec", "url": "jdbc:mysql://10.9."}'

对象获取参数配置方式,直接配置键值对,不能是json格式:

java 复制代码
db:
  connectInfo: 
    user: kengcoder
    password:  XDIxde!322332ec
    url: "jdbc:mysql://10.9.2.7:3306/accountdb"

3. 总结

本文介绍了Spring的配置参数能力,其参数来源支持从配置文件和环境变量获取,文件格式支持properties和yaml,参数格式支持单值,数组,List和Map。

总体来看Spring的配置属于静态配置,缺少动态刷新(例如定期修改数据库密码),版本管理等能力,在选型时要结合实际业务场景判断是否满足要求。


其他阅读:

萌新快速成长之路
如何编写软件设计文档
Spring Cache架构、机制及使用
布隆过滤器适配Spring Cache及问题与解决策略
JAVA编程思想(一)通过依赖注入增加扩展性
JAVA编程思想(二)如何面向接口编程
JAVA编程思想(三)去掉别扭的if,自注册策略模式优雅满足开闭原则
Java编程思想(七)使用组合和继承的场景
JAVA基础(一)简单、透彻理解内部类和静态内部类
JAVA基础(二)内存优化-使用Java引用做缓存
JAVA基础(三)ClassLoader实现热加载
JAVA基础(五)函数式接口-复用,解耦之利刃

相关推荐
张某布响丸辣6 分钟前
SQL中的时间类型:深入解析与应用
java·数据库·sql·mysql·oracle
喜欢打篮球的普通人12 分钟前
rust模式和匹配
java·算法·rust
java小吕布25 分钟前
Java中的排序算法:探索与比较
java·后端·算法·排序算法
慢生活的人。31 分钟前
SpringSecurity+jwt+captcha登录认证授权总结
java·认证·rbac·权限·验证
2401_857600951 小时前
深入剖析:Spring MVC与Struts的较量
struts·spring·mvc
被猫枕的咸鱼1 小时前
springmvc通过使用map来进行数据的接收和使用
spring
Goboy1 小时前
工欲善其事,必先利其器;小白入门Hadoop必备过程
后端·程序员
向阳12181 小时前
LeetCode40:组合总和II
java·算法·leetcode
云空1 小时前
《InsCode AI IDE:编程新时代的引领者》
java·javascript·c++·ide·人工智能·python·php
慧都小妮子1 小时前
Spire.PDF for .NET【页面设置】演示:复制 PDF 文档中的页面
java·pdf·.net