You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot项目中application.yml自定义类List无法读取的问题求助

问题描述

我在Spring Boot 2.3.4版本的项目里读取application.yml配置时碰到了个棘手的问题:一开始所有配置都读成null,清理重建项目后其他配置都正常了,但自定义类的List<LogComponent>始终还是null。试了各种办法都没解决,麻烦帮忙看看代码里哪里出问题了?

相关代码

配置类 TestAPIConfiguration

@Configuration
@EnableConfigurationProperties
@ConfigurationProperties
public class TestAPIConfiguration {
    private String eventCache;
    private String diskBasedCache;
    private List<String> sendAllSMSto;
    private List<String> sendAllEmailsto;
    // 这个属性明明yml里有值,但始终读成null
    private List<LogComponent> logComponents;
    @NotNull
    private String selfURIPrefix;
    @NotNull
    private String investURIPrefix;
    @NotNull
    private String ifaURIPrefix;
    private String apiEnv;
    private final Joiner joiner = Joiner.on( "," ).skipNulls();
    private static final Logger LOGGER = LoggerFactory.getLogger(TestAPIConfiguration.class);

    @PostConstruct
    public void setSystemProperties() {
        try {
            System.setProperty(SystemConstants.EVENT_CACHE_PATH, eventCache);
            System.setProperty(SystemConstants.DISK_BASED_CACHE_PATH, diskBasedCache);
            System.setProperty(SystemConstants.REQUEST_LOGGING_FIELDS, JSONUtils.getObjectMapper().writeValueAsString(logComponents));
            System.setProperty(SystemConstants.ENVIRONMENT_IDENTIFIER, apiEnv);
            System.setProperty(INVEST_URI_PREFIX, investURIPrefix);
            System.setProperty(IFA_URI_PREFIX, ifaURIPrefix);
            if(sendAllSMSto != null)
                System.setProperty(SEND_ALL_SMS_TO, joiner.join(sendAllSMSto));
            if(sendAllEmailsto != null)
                System.setProperty(SystemConstants.SEND_ALL_EMAILS_TO, joiner.join(sendAllEmailsto));
        } catch(Exception se) {
            LOGGER.error("Error in Configuration Setup: {}", se.getLocalizedMessage());
        }
    }

    public String getEventCache() { return eventCache; }
    public void setEventCache(String eventCache) { this.eventCache = eventCache; }
    public String getDiskBasedCache() { return diskBasedCache; }
    public void setDiskBasedCache(String diskBasedCache) { this.diskBasedCache = diskBasedCache; }
    public List getSendAllSMSto() { return sendAllSMSto; }
    public void setSendAllSMSto(List<String> sendAllSMSto) { this.sendAllSMSto = sendAllSMSto; }
    public List getSendAllEmailsto() { return sendAllEmailsto; }
    public void setSendAllEmailsto(List<String> sendAllEmailsto) { this.sendAllEmailsto = sendAllEmailsto; }
    public List getRequestLoggingFields() { return logComponents; }
    public void setRequestLoggingFields(List<LogComponent> requestLoggingFields) { this.logComponents = requestLoggingFields; }
    public String getSelfURIPrefix() { return selfURIPrefix; }
    public void setSelfURIPrefix(String selfURIPrefix) { this.selfURIPrefix = selfURIPrefix; }
    public String getInvestURIPrefix() { return investURIPrefix; }
    public void setInvestURIPrefix(String investURIPrefix) { this.investURIPrefix = investURIPrefix; }
    public String getIfaURIPrefix() { return ifaURIPrefix; }
    public void setIfaURIPrefix(String ifaURIPrefix) { this.ifaURIPrefix = ifaURIPrefix; }
    public String getApiEnv() { return apiEnv; }
    public void setApiEnv(String apiEnv) { this.apiEnv = apiEnv; }
}

自定义类 LogComponent

@Component
public class LogComponent {
    @NotNull
    private String headerName;
    @NotNull
    private String sessionKey;
    @NotNull
    private String logPrintKey;

    public String getHeaderName() { return headerName; }
    public String getSessionKey() { return sessionKey; }
    public String getLogPrintKey() { return logPrintKey; }
}

application.yml 配置

debug: true
server:
  port: 8080
apiEnv: UAT
selfURIPrefix: "https://testurl.localhost.net"
investURIPrefix: "https://testurl.mediaserver.net"
ifaURIPrefix: "https://testurl.secondaryserver.net"
sendAllSMSto:
  - "0000000000"
sendAllEmailsto:
  - "abc@testmail.com"
eventCache: "C:\\Users\\username\\project\\devnull\\eventcachepurchase.mdb"
diskBasedCache: "C:\\Users\\username\\project\\devnull\\cache.mdb"
logComponents:
  - headerName: X-RT-REQUEST-TRACKER
    sessionKey: NOT AVAILABLE
    logPrintKey: REQUEST-TRACKER
  - headerName: X-RT-INX-DWD
    sessionKey: IFX-PDR
    logPrintKey: PDR_NO
  - headerName: X-RT-IFA-ARN
    sessionKey: IRX-AXRN
    logPrintKey: AXR-CDODEEE
问题排查与原因分析

我帮你梳理了下代码,发现两个核心问题:

  • 属性映射不匹配:你在TestAPIConfiguration里定义的属性是logComponents,但对应的getter是getRequestLoggingFields()、setter是setRequestLoggingFields()。Spring Boot的配置绑定是通过getter/setter的名称来匹配yml中的键的,这俩名字对不上,Spring根本不知道要把yml里的logComponents绑定到这个属性上,自然就返回null了。
  • LogComponent缺少赋值必要条件:这个类加了@Component注解,但作为配置属性的承载类,Spring需要通过setter方法给它的属性赋值,可你现在只有getter没有setter;另外,Spring实例化配置类对象时需要无参构造器,你也没添加,这就导致即使前面的映射对了,Spring也没法实例化并填充LogComponent对象。
解决方案

按照下面的步骤修改代码就能解决问题:

  1. 修正TestAPIConfiguration的getter/setter命名
    把getRequestLoggingFields()和setRequestLoggingFields()改成和属性名一致的getLogComponents()和setLogComponents(),这样Spring才能正确匹配yml里的logComponents键。修改后的代码片段:
public List<LogComponent> getLogComponents() { 
    return logComponents; 
}
public void setLogComponents(List<LogComponent> logComponents) { 
    this.logComponents = logComponents; 
}
  1. 修正LogComponent类
  • 去掉@Component注解:这个类是用来承载配置的,不需要被Spring作为Bean管理(除非你有其他特殊用途);
  • 添加无参构造器:Spring实例化配置类对象时需要;
  • 给每个属性添加setter方法:Spring需要通过这些方法给属性赋值。

修改后的LogComponent代码:

public class LogComponent {
    @NotNull
    private String headerName;
    @NotNull
    private String sessionKey;
    @NotNull
    private String logPrintKey;

    // 添加无参构造器
    public LogComponent() {}

    public String getHeaderName() { return headerName; }
    public void setHeaderName(String headerName) { this.headerName = headerName; }
    
    public String getSessionKey() { return sessionKey; }
    public void setSessionKey(String sessionKey) { this.sessionKey = sessionKey; }
    
    public String getLogPrintKey() { return logPrintKey; }
    public void setLogPrintKey(String logPrintKey) { this.logPrintKey = logPrintKey; }
}
  1. 可选优化(非必须)
    你可以给TestAPIConfiguration的@ConfigurationProperties注解加上prefix,比如@ConfigurationProperties(prefix = "api"),然后把yml里的配置项都加上api.前缀,这样配置结构会更清晰,不过这一步不影响当前问题的解决,看你自己的需求来加就行。

内容的提问来源于stack exchange,提问作者Hitesh Kirtane

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 17:22:29