1. 概述

在 Spring Boot 应用中,一个常见的需求是将外部配置属性注入到 Spring Bean 中。通常我们会使用 @ConfigurationProperties 注解将一组配置绑定到一个类中。但如果我们只需要注入几个独立的配置项,也可以使用 @Value 注解来实现。

本文将介绍如何在 Kotlin 中使用 @Value 注解注入配置属性。

2. YAML 配置文件

我们首先在 src/main/resources 目录下创建一个名为 application-inject-value.yml 的 YAML 配置文件:

my-app:
  magic-number: 42
  magic-string: "It's a magic string"
  magic-flag: true

  magic-string-with-default: "It's another magic string"

⚠️ Spring 默认不支持从 YAML 文件加载配置到 @PropertySource,所以我们需要自定义一个 YamlPropertySourceFactory 类来支持 YAML:

class YamlPropertySourceFactory : PropertySourceFactory {
    override fun createPropertySource(@Nullable name: String?, encodedResource: EncodedResource): PropertySource<*> =
      PropertiesPropertySource(encodedResource.resource.filename,
        YamlPropertiesFactoryBean().also { it.setResources(encodedResource.resource) }.getObject()
      )
}

然后,我们在 Spring Boot 主类上使用 @PropertySource 注解加载这个 YAML 文件:

@PropertySource(value = ["classpath:application-inject-value.yml"], factory = YamlPropertySourceFactory::class)
@SpringBootApplication(scanBasePackages = ["com.baeldung.theValueAnnotation"])
class KotlinValueInjectionApplication

接下来,我们就可以在组件中使用 @Value 注解注入这些配置了。

3. 使用 @Value 注入配置属性

在 Java 中,我们通常使用 @Value("${prop.name}") 的方式注入配置。但在 Kotlin 中,由于字符串模板也使用 $ 符号,**我们需要对 $ 进行转义,写成 \${**。

我们创建一个 Spring 组件来演示注入:

@Component
class ValueBean(
  @Value("\${my-app.magic-number}")
  val magicNumber: Int,
  @Value("\${my-app.magic-string}")
  val magicString: String,
  @Value("\${my-app.magic-flag}")
  val magicFlag: Boolean,
)

✅ 这里我们使用了构造器注入方式注入配置属性,简洁又符合 Kotlin 风格。

为了验证注入是否成功,我们可以编写一个测试类:

@SpringBootTest
@TestConstructor(autowireMode = AutowireMode.ALL)
class TheValueAnnotationUnitTest(val valueBean: ValueBean) {

    @Test
    fun `test injected values`() {
        with(valueBean) {
            assertEquals(42, magicNumber)
            assertEquals("It's a magic string", magicString)
            assertTrue(magicFlag)
        }
    }
}

测试通过说明配置项已正确注入。

4. 使用默认值注入

有时候,我们希望为配置项提供一个默认值,以应对配置文件中可能缺失的情况。使用 @Value("${prop.name:default}") 格式即可实现

我们扩展 ValueBean 类,添加两个带默认值的字段:

@Component
class ValueBean(
  ... 
  // 带默认值的字段
  @Value("\${my-app.not-defined-value:1024}")
  val magicNumberWithDefault: Int,
  @Value("\${my-app.magic-string-with-default:default Value}")
  val magicStringWithDefault: String,
)

配置中 my-app.not-defined-value 并不存在,所以会注入默认值 1024;而 my-app.magic-string-with-default 已定义,所以会注入配置值。

测试代码如下:

with(valueBean) {
    assertEquals(1024, magicNumberWithDefault)
    assertEquals("It's another magic string", magicStringWithDefault)
}

5. 使用 null 作为默认值

除了非空默认值,我们有时也希望在配置缺失时使用 null 作为默认值。

在 Kotlin 中,**字段必须声明为可空类型(如 String?)才能接受 null**。我们继续扩展 ValueBean

@Component
class ValueBean(
  ...
  // 使用 null 作为默认值
  @Value("\${my-app.not-defined-value:null}")
  val stringDefaultLiteralNull: String?,
  @Value("\${my-app.not-defined-value:#{null}}")
  val stringDefaultNull: String?
)

这两个字段虽然都试图注入不存在的配置项,但行为略有不同:

  • \${my-app.not-defined-value:null}:注入字符串 "null"
  • \${my-app.not-defined-value:#{null}}:注入 null,因为 #{null} 是 Spring 表达式(SpEL)中的 null 字面量。

测试代码如下:

with(valueBean) {
    assertEquals("null", stringDefaultLiteralNull)
    assertNull(stringDefaultNull)
}

⚠️ 注意:"null" 是字符串,不是真正的 null,容易踩坑!

6. 小结

本文介绍了如何在 Kotlin + Spring Boot 项目中使用 @Value 注解注入配置属性,包括:

✅ 使用 YAML 配置并加载到 Spring 上下文中
✅ Kotlin 中使用 @Value("\${...}") 注入配置
✅ 提供默认值:@Value("\${prop:default}")
✅ 使用 null 作为默认值:@Value("\${prop:#{null}}")
✅ 注意 Kotlin 的可空类型限制

完整代码可在 GitHub 上查看。


原始标题:Kotlin and Spring Boot: Injecting Configuration Properties Using @Value