首页 > 其他分享 >Spring的@Value注解和SpringBoot yml配置项目实战踩坑总结

Spring的@Value注解和SpringBoot yml配置项目实战踩坑总结

时间:2024-07-06 22:09:38浏览次数:5  
标签:code SpringBoot Spring xxx private Value null config

知识点

Spring提供了@Value注解,可用于将配置文件或注册中心的属性值动态注入到Bean中。

注:@Value注解在spring-beans包里。

  1. @Value("${...}"):注入获取对应属性文件中定义的属性值;
  2. @Value("#{...}"):表示SpEl表达式通常用来获取Bean的属性;

实例

/**
 * 服务内动态配置
 *
 * @author cdfive
 */
@Slf4j
@Getter
@Setter
@RefreshScope
@Configuration
public class DynamicConfig implements Serializable {

    // 服务内部错误代码
    @Value("${xxx.dynamic.serviceError.code:500}")
    private Integer serviceErrorCode;

    // 服务内部错误消息
    @Value("${xxx.dynamic.serviceError.msg:服务繁忙,请稍候再试}")
    private String serviceErrorMsg;
    
    // RPC日志是否启用
    @Value("${xxx.dynamic.rpcLogEnable:true}")
    private boolean rpcLogEnable;
    
    // 业务内部线程池核心线程数
    @Value("${xxx.dynamic.bizInteralThreadPool.coreSize:4}")
    private int bizInteralThreadPoolCoreSize;

    ...

    // 跟踪的商品编码集合
    @Value("${xxx.dynamic.trace.productCode:#{null}}")
    private String traceProductCode;

通过@Value("${xxx}")Bean里的字段映射配置文件的值,如application.yml

xxx:
  dynamic:
    serviceError:
      code: 500
      msg: 系统维护中,请稍候再试
    trace:
      productCode: 100000001

注意点1---默认值

如果配置文件里没有xxx的配置,则@Value("${xxx}")需要指定默认值,否则启动应用报错。

例如:

@Value("${error.code.msg}")
private Integer errorCodeMsg;

应用启动报错:

Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'error.code.msg' in value "${error.code.msg}"
	at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:180)
	at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126)
	at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:239)
	at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:210)

通过:分隔后面加上默认值。
例如:

@Value("${error.code.success:200}")
private Integer errorCodeSuccess;

如果外部没有配置codeSuccess,则它的默认值为200。

当属性为IntegerStringBoolean对象类型,如果希望外部没有配置时,默认为null,则在:后加上#{null}
例如:

@Value("${error.code.msg:#{null}}")
private String errorCodeMsg;

如果只写:String类型默认值为空字符串"";
例如:

@Value("${error.code.msg:}")
private String errorCodeMsg;

注:对于IntegerLong类型,xxx:#{null}xxx:效果相同,默认值为null

注意点2---集合类型

List,Set类型,集合每一项值通过英文逗号,分隔

@Value("${global.config.nums}")
private List<Integer> nums;

@Value("${global.config.items}")
private Set<String> items;
global:
  config:
    nums: 1,2,3
    items: aa,bb,cc

如果不想在yml配置,可在Bean里指定默认值:

@Value("${global.config.nums:1,2,3}")
private List<Integer> nums;

@Value("${global.config.items:aa,bb,cc}")
private Set<String> items;

如果想Bean的集合字段默认值为null,等有需要时再去yml里配置,则加上:#{null}即可。

@Value("${global.config.nums:#{null}}")
private List<Integer> nums;

@Value("${global.config.items:#{null}}")
private Set<String> items;

如果想Bean的集合字段默认值为空集合,等有需要时再去yml里配置,则加上:即可。

@Value("${global.config.nums:}")
private List<Integer> nums;

@Value("${global.config.items:}")
private Set<String> items;

默认空集合可不用null判断,避免NPE空指针异常。

注意点3---SpEL表达式

使用split方法,英文逗号分隔

@Value("#{'${xxx.dynamic.codes:111,222}'.split(',')}")
private List<String> codes;

注意这种方式:
1.如果不填默认值,且外部配置没有:

@Value("#{'${xxx.dynamic.codes}'.split(',')}")
private List<String> codes;

则启动报错Could not resolve placeholder

2.默认值里不能用#{null}

@Value("#{'${xxx.dynamic.codes:#{null}}'.split(',')}")
private List<String> codes;

整个会被当作字符串解析,解析结果为列表里只有1个元素,值为#{null}

3.写:也不行

@Value("#{'${xxx.dynamic.codes:#{null}}'.split(',')}")
private List<String> codes;

解析结果为列表里只有1个元素,值为空字符串""

如果想代码里不填默认值,且允许外部不配置,此时列表为空列表:
可考虑自定义方法decodeList

@SuppressWarnings("rawtypes")
public static List<String> decodeList(String value) {
    if (StringUtils.isBlank(value)) {
        return Collections.emptyList();
    }

    return Splitter.on(",").omitEmptyStrings().splitToList(value).stream().collect(Collectors.toList());
}

通过#{T(包名.类名).方法名('${...}')}使用自定义方法:

@Value("#{T(xxx.DynamicConfig).decodeList('${xxx.dynamic.codes}')}")
private List<String> codes;

Map类型,自定义方法decodeMap

@SuppressWarnings("rawtypes")
public static Map decodeMap(String value) {
    if (StringUtils.isBlank(value)) {
        return Collections.emptyMap();
    }

    return JsonUtils.json2Obj(value, Map.class);
}

属性设置:

@Value("#{T(xxx.DynamicConfig).decodeMap('${xxx.dynamic.channelTypes}')}")
private Map<String, List<String>> channelTypes;

外部配置:

xxx:
  dynamic:
    channelTypes: '{"aa":["xx","yy"],"bb":["zz"]}'

补充1

SpringBoot在Spring的基础上,提供了更多的注解用于配置管理,如:@ConfigurationPropertiesEnableConfigurationProperties等。

例:

@Data
@ConfigurationProperties(prefix = "xxx.config")
public class XxxProperties {

    private Boolean enable;
    
    private String code;
   
    ...
}
@Slf4j
@Configuration
@EnableConfigurationProperties(XxxProperties.class)
public class XxxAutoConfig {
    ...
}

其中:

  • @ConfigurationProperties(prefix = "xxx.config")把类的属性与yml配置文件里配置进行绑定;
  • @EnableConfigurationProperties(XxxProperties.class),将XxxProperties.class添加至Spring容器;
  • 也可不使用@EnableConfigurationProperties,那么XxxProperties.class需要通过其他方式添加至Spring容器,如标记注解@Component

补充2

外部配置,如项目里的application.yml文件、或者Nacos配置中心里yml配置,如果属性类型为String,属性值为0开头,则属性值需要加上双引号

配置类:

@Value("${xxx.config.codes}")
private String code;

yml文件:

xxx:
  config:
    code: 048

项目启动,发现code值不是期望的048,而是48.0

修改yml文件:

xxx:
  config:
    code: "048"

再次重启项目,code值为预期的048

标签:code,SpringBoot,Spring,xxx,private,Value,null,config
From: https://www.cnblogs.com/cdfive2018/p/18282127

相关文章

  • 基于SpringBoot+Vue的招生管理系统(带1w+文档)
    基于SpringBoot+Vue的招生管理系统(带1w+文档)通过招生管理系统的研究可以更好地理解系统开发的意义,而且也有利于发展更多的智能系统,解决了人才的供给和需求的平衡问题,招生管理系统的开发建设,由于其开发周期短,维护方便,所以它可以适应招生公告体系基本要求。项目简介基于......
  • 【计算机毕业设计】springboot房屋租赁系统的设计与实现
    随着社会的不断进步与发展,人们经济水平也不断的提高,于是对各行各业需求也越来越高。特别是从2019年新型冠状病毒爆发以来,利用计算机网络来处理各行业事务这一概念更深入人心,由于工作繁忙以及疫情的原因,用户到房源公司进行房屋求租也是比较难实施的。如果开发一款房屋租赁系......
  • Spring Boot 自定义 starter 启动器
    前言:SpringBoot为我们提供了自动配置的功能,我们可以像使用插件一样,对各个组件自由组合装配,只需引入定义好的starter即可,有点类似于Java的SPI机制,SPI机制是为了解决项目与项目之间的解耦,而SpringBootstarter方式实现了模块化的解耦,前文我们从SpringBooot源......
  • springboot长江航运管理系统-计算机毕业设计源码54774
    摘 要随着科学技术的飞速发展,社会的方方面面、各行各业都在努力与现代的先进技术接轨,通过科技手段来提高自身的优势,长江航运公司当然也不例外。长江航运管理系统是以实际运用为开发背景,运用软件工程原理和开发方法,采用Java技术构建的一个管理系统。整个开发过程首先对软件......
  • SpringBoot引入WebSocket
    WebSocket是一种在客户端和服务器之间提供低延迟、全双工通信的网络协议。它允许双方在建立一次连接后,进行实时、持续的数据交换,无需像HTTP那样为每一个请求和响应建立新的连接。WebSocket的设计初衷是解决传统HTTP协议在实时通信方面的不足,比如实现实时聊天、游戏、股票报价等......
  • 【SpringBoot】SpringBoot自动装配原理
    在上一篇文章中,讲述了SpringBoot核心启动流程源码解析其中,主要是构造方法和run方法的处理,本篇接着准备上下文环境后续,讲述是如何将springboot是如何完成自动装配,主线其实就是什么时候完成对主类的加载,也即对SpringBootApplication类加载到IOC容器中什么时候完成对Spring......
  • A value of type 'Scaffold?' can't be assigned to a variable of type 'Scaffold&#0
    原来的代码classContextRouteextendsStatelessWidget{constContextRoute();@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text("Context测试"),),body:Container(......
  • SpringBoot如何集成和使用开源工作流引擎camunda
    使用camunda开源工作流引擎有:通过docker运行、使用springboot集成、部署camunda发行包、基于源代码编译运行等多种方式。其中,通过源代码编译运行的方式最为复杂,具体参考:https://lowcode.blog.csdn.net/article/details/136206057文本重点介绍如何在SpringBoot应用程序中如何集......
  • spring-关于组件的注入及获取流程
    一、组件注入的基本流程:容器初始化:Spring应用启动时,会读取配置(如XML配置、注解配置等),并根据这些配置创建Bean定义(BeanDefinition)。根据Bean定义,Spring容器实例化Bean,并管理它们之间的依赖关系。依赖解析与注入:当一个Bean依赖于另一个Bean时,Spring容器负责查找并注入这个依赖......
  • spring cloud 上云的情况下,Ribbon 客户端负载均衡 与 ALB 服务端负载均衡的选择
    在云环境(例如AWS)中,由于云提供商通常提供强大的负载均衡服务(如AWS的ALB),一般不再需要使用Ribbon这种客户端负载均衡方案。云环境中的负载均衡器通常能够提供更高的可靠性、可扩展性和简化的配置,因此在上云的情况下,使用云提供的负载均衡器是更优的选择。理由分析云提供的负载均衡......