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

如何在非Bean类(静态类)中读取application.yaml属性?

原实现的问题分析
  • 类加载顺序风险:FooUtil作为object会在首次被访问时初始化,若它在CustomEnvironmentPostProcessor.postProcessEnvironment执行前就被加载,拿到的会是property的默认值true,而非配置文件中的实际值——因为Spring的EnvironmentPostProcessor执行时机在应用启动早期,但类加载顺序不受Spring控制。
  • 违背Spring设计规范:EnvironmentPostProcessor的定位是修改环境配置的处理器,本身应保持无状态。用单例object持有可变配置属性,既违背了该接口的设计初衷,在多环境初始化场景下还可能引发线程安全问题。
  • 默认值维护性差:默认值硬编码在代码中,没有利用Spring配置的默认值机制,后续修改不够灵活。
推荐改进方案

方案1:使用@ConfigurationProperties绑定配置(Spring官方推荐)

这种方式能优雅完成配置绑定,彻底规避类加载顺序问题。

首先定义配置类:

@ConfigurationProperties(prefix = "foo")
class FooProperties {
    var bar: Boolean = true // 在这里设置默认值
}

在启动类添加注解启用配置绑定:

@SpringBootApplication
@EnableConfigurationProperties(FooProperties::class)
class YourApplication

fun main(args: Array<String>) {
    runApplication<YourApplication>(*args)
}

若FooUtil必须是静态类,可通过Spring上下文注入配置类,用@PostConstruct完成静态属性初始化:

@Component
object FooUtil {
    private lateinit var fooProperties: FooProperties

    @Autowired
    fun setFooProperties(properties: FooProperties) {
        fooProperties = properties
    }

    // 示例业务方法
    fun doSomething() {
        val barValue = fooProperties.bar
        // 编写业务逻辑
    }
}

注意:给FooUtil加上@Component注解,确保Spring能扫描到并自动注入FooProperties。

方案2:直接注入Environment到工具类(适合简单场景)

如果不想使用@ConfigurationProperties,可以直接将Spring的Environment注入工具类,延迟获取配置值:

@Component
object FooUtil {
    @Autowired
    private lateinit var environment: Environment

    private val barProperty: Boolean by lazy {
        environment.getProperty("foo.bar", Boolean::class.java) ?: true
    }

    fun useProperty() {
        println(barProperty)
    }
}

这种方式避免了提前初始化问题,因为每次调用相关方法时才从Environment中取值,而Environment在Spring启动完成后已包含所有配置。

方案3:保留EnvironmentPostProcessor但修正实现(不推荐,仅作参考)

若一定要用EnvironmentPostProcessor,需让它回归本职工作(处理环境配置),配置读取交给工具类通过Spring上下文完成:

class CustomEnvironmentPostProcessor : EnvironmentPostProcessor {
    private const val CONFIG_PROPERTY = "foo.bar"

    override fun postProcessEnvironment(environment: ConfigurableEnvironment, application: SpringApplication?) {
        val defaultValue = "true"
        val propertyValue = StringUtils.trimWhitespace(environment.getProperty(CONFIG_PROPERTY) ?: defaultValue)
        // 若原配置不存在,将默认值加入环境
        if (!environment.containsProperty(CONFIG_PROPERTY)) {
            environment.propertySources.addFirst(
                MapPropertySource("custom-foo-bar", mapOf(CONFIG_PROPERTY to propertyValue))
            )
        }
    }
}

@Component
object FooUtil {
    @Autowired
    private lateinit var environment: Environment

    private val barProperty: Boolean by lazy {
        environment.getProperty("foo.bar", Boolean::class.java) ?: true
    }

    fun useProperty() {
        println(barProperty)
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 22:54:32