使用 @Value

@Value 通常用于注入外部化属性

  • Java

  • Kotlin

@Component
public class MovieRecommender {

    private final String catalog;

    public MovieRecommender(@Value("${catalog.name}") String catalog) {
        this.catalog = catalog;
    }
}
@Component
class MovieRecommender(@Value("\${catalog.name}") private val catalog: String)

使用以下配置

  • Java

  • Kotlin

@Configuration
@PropertySource("classpath:application.properties")
public class AppConfig { }
@Configuration
@PropertySource("classpath:application.properties")
class AppConfig

以及以下 application.properties 文件

catalog.name=MovieCatalog

在这种情况下,catalog 参数和字段将等于 MovieCatalog 值。

Spring 提供了一个默认的宽松嵌入值解析器。它将尝试解析属性值,如果无法解析,则属性名称(例如 ${catalog.name})将被注入为值。如果您希望严格控制不存在的值,则应声明一个 PropertySourcesPlaceholderConfigurer Bean,如下例所示

  • Java

  • Kotlin

@Configuration
public class AppConfig {

	@Bean
	public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
		return new PropertySourcesPlaceholderConfigurer();
	}
}
@Configuration
class AppConfig {

	@Bean
	fun propertyPlaceholderConfigurer() = PropertySourcesPlaceholderConfigurer()
}
使用 JavaConfig 配置 PropertySourcesPlaceholderConfigurer 时,@Bean 方法必须是 static 的。

使用上述配置可确保如果任何 ${} 占位符无法解析,则 Spring 初始化失败。还可以使用 setPlaceholderPrefixsetPlaceholderSuffixsetValueSeparatorsetEscapeCharacter 等方法来自定义占位符。

Spring Boot 默认配置了一个 PropertySourcesPlaceholderConfigurer Bean,它将从 application.propertiesapplication.yml 文件中获取属性。

Spring 提供的内置转换器支持允许简单类型转换(例如转换为 Integerint)自动处理。多个逗号分隔的值可以自动转换为 String 数组,无需额外操作。

可以提供默认值,如下所示

  • Java

  • Kotlin

@Component
public class MovieRecommender {

    private final String catalog;

    public MovieRecommender(@Value("${catalog.name:defaultCatalog}") String catalog) {
        this.catalog = catalog;
    }
}
@Component
class MovieRecommender(@Value("\${catalog.name:defaultCatalog}") private val catalog: String)

Spring BeanPostProcessor 在后台使用 ConversionService 处理将 @Value 中的 String 值转换为目标类型。如果您希望为自己的自定义类型提供转换支持,则可以提供自己的 ConversionService Bean 实例,如下例所示

  • Java

  • Kotlin

@Configuration
public class AppConfig {

    @Bean
    public ConversionService conversionService() {
        DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
        conversionService.addConverter(new MyCustomConverter());
        return conversionService;
    }
}
@Configuration
class AppConfig {

	@Bean
	fun conversionService(): ConversionService {
		return DefaultFormattingConversionService().apply {
			addConverter(MyCustomConverter())
		}
	}
}

@Value 包含 SpEL 表达式 时,值将在运行时动态计算,如下例所示

  • Java

  • Kotlin

@Component
public class MovieRecommender {

    private final String catalog;

    public MovieRecommender(@Value("#{systemProperties['user.catalog'] + 'Catalog' }") String catalog) {
        this.catalog = catalog;
    }
}
@Component
class MovieRecommender(
	@Value("#{systemProperties['user.catalog'] + 'Catalog' }") private val catalog: String)

SpEL 还支持使用更复杂的数据结构

  • Java

  • Kotlin

@Component
public class MovieRecommender {

    private final Map<String, Integer> countOfMoviesPerCatalog;

    public MovieRecommender(
            @Value("#{{'Thriller': 100, 'Comedy': 300}}") Map<String, Integer> countOfMoviesPerCatalog) {
        this.countOfMoviesPerCatalog = countOfMoviesPerCatalog;
    }
}
@Component
class MovieRecommender(
	@Value("#{{'Thriller': 100, 'Comedy': 300}}") private val countOfMoviesPerCatalog: Map<String, Int>)