Spring配置类的演化

一.引言:一个配置失效引发的思考

java 复制代码
package com.example.demo.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Slf4j
@Component
@PropertySource(value = {"classpath:app.properties"}, ignoreResourceNotFound = true)
public class ServiceDomainConfig {
@Value("${service.domain.url}")
private String url;

@Value("${service.domain.accessKey}")
private String accessKey;

public String getUrl() {
    return url;
}

public String getAccessKey() {
    return accessKey;
}

@PostConstruct
public void init() {
    log.info("ServiceDomainConfig loading...");
    log.info("  url: {}", url == null ? "NULL" : "OK");
    log.info("  accessKey: {}", accessKey == null ? "NULL" : "OK ***");

    if (isEmpty(url)) {
        throw new IllegalArgumentException(
            "ServiceDomainConfig validation failed: service.domain.url is empty. " +
            "Please check app.properties configuration."
        );
    }
    if (isEmpty(accessKey)) {
        throw new IllegalArgumentException(
            "ServiceDomainConfig validation failed: service.domain.accessKey is empty. " +
            "Please check app.properties configuration."
        );
    }

    log.info("ServiceDomainConfig validation passed");
}

private boolean isEmpty(String value) {
    return value == null || value.trim().isEmpty();
}
}

如果在ssm项目中不配置PropertyPlaceholderConfigurer,上面的类启动便会报错,即使@PropertySource指定了配置文件也没用,因为@Value注解里面的值无法被解析。

二.SSM项目配置

正确的配置如下:

xml文件中需要配置PropertyPlaceholderConfigurer

java 复制代码
<!-- 必须手动配置 -->
<bean class="PropertyPlaceholderConfigurer">
    <property name="location" value="classpath:app.properties"/>
</bean>

或者

java 复制代码
<!-- applicationContext.xml -->
<context:property-placeholder 
    location="classpath:app.properties" 
    ignore-resource-not-found="true"
    ignore-unresolvable="false"/>

该配置会在没找到属性资源时自动忽略对应属性。而且还可以配置从环境变量里面找值,这里就没有配置。

对应配置类如下:

java 复制代码
package com.test.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import javax.annotation.PostConstruct;

/**
 * OSFP 通知平台配置
 *
 * @Date 2022/05/24
 * @Author linxl
 */
@Slf4j
@Configuration
@PropertySource(value = {"classpath:sys.properties"}, ignoreResourceNotFound = true)
public class OsfpApiConfig {

    @Value("${notice.url}")
    private String url;

    @Value("${notice.appid}")
    private String clientId;

    @Value("${notice.appSecret}")
    private String clientSecret;

    @Value("${notice.grantType}")
    private String grantType;

    @Value("${notice.lamsUrl}")
    private String issUrl;

    @PostConstruct
    public void init() {
        log.info("OsfpApiConfig 初始化完成 - URL: {}, ClientId: {}", url, clientId);
    }

    public String getUrl() {
        return url;
    }

    public String getClientId() {
        return clientId;
    }

    public String getClientSecret() {
        return clientSecret;
    }

    public String getGrantType() {
        return grantType;
    }

    public String getIssUrl() {
        return issUrl;
    }
}

通过这种方式便能够解析@value属性里面的值,其实@PropertySource注解也可以省略。因为通过xml的方式已经加载了对应的配置文件,并把里面的属性注入到了spring的environment里面,@Value可以正常拿到值。

三.springboot项目的配置

然而boot项目简化了许多,我们不需要配置PropertyPlaceholderConfigurer或其子类,通过下面的方式就能绑定配置文件并拿到值,而且不用加@Value注解,不用指定层级,自动可以解析相关属性。

配置类如下:

java 复制代码
package com.test.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

/**
 * 通知平台配置
 *
 * @Date 2022/05/24
 * @Author linxl
 */
@Configuration
@ConfigurationProperties(prefix = "osfp")
public class OsfpApiConfig {

    String clientId;
    String clientSecret;
    String grantType;

    public String getClientId() {
        return clientId;
    }

    public void setClientId(String clientId) {
        this.clientId = clientId;
    }

    public String getClientSecret() {
        return clientSecret;
    }

    public void setClientSecret(String clientSecret) {
        this.clientSecret = clientSecret;
    }

    public String getGrantType() {
        return grantType;
    }

    public void setGrantType(String grantType) {
        this.grantType = grantType;
    }
}

application.xml配置文件如下:

java 复制代码
osfp:
  url: http://open-trest.sit.sf-express.com:8080
  clientId: adfcd86498d04f0ba14d5775a20c0b18
  clientSecret: bde733ffd494446794cab3e8bcc1701f
  grantType: client_credentials
相关推荐
guodingdingh1 小时前
软件开发工作问题总结0718
java·开发语言·数据库
咖啡八杯3 小时前
GoF设计模式——解释器模式
java·后端·spring·设计模式
优橙教育3 小时前
5G网优培训 vs Java开发:转行选哪个?
java·开发语言·5g
糖果店的幽灵3 小时前
【DeepAgents 从入门到精通】Context Management 上下文管理
java·人工智能·后端·spring·中间件·langgraph·deepagents
腻害兔4 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:字典、短信、邮件、通知——后台系统的“基础设施四件套“!
java·前端·vue.js·产品经理·ai编程
碎光拾影5 小时前
ARM交叉工具链各工具作用及IMX6ULL平台LED+蜂鸣器裸机程序实现
java·开发语言·数据库
Miao121316 小时前
微服务 API 测试实践:海外某民宿平台如何构建模式驱动测试基础设施
java·开发语言
腻害兔6 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:支付模块 yudao-module-pay,一个让产品经理都看懂的支付中台设计
java·前端·vue.js·产品经理·ai编程
CRMEB系统商城7 小时前
开源自建还是SaaS订阅?算一笔3年经济账
java·大数据·开发语言·开源
keyipatience8 小时前
线程栈与TLS和线程互斥
java·linux·服务器·开发语言·ubuntu