如果你和我一样,曾经被 Spring 中 @Value
注解中的“{property.key}")
来获取配置,但有些场景下突然需要使用
#`,不禁让人疑惑:这两者究竟差别在哪儿?用错了会有什么后果?
下面就带大家一起深入了解 @Value("${...}")
和 @Value("#{...}")
的区别,并用简单易懂的例子来解释各自的应用场景。
一、“$” 和 “#” 的区别:属性值 vs. SpEL 表达式
在 Spring 中,@Value
注解支持两种主要语法:
-
@Value("${...}")
:用于属性值的占位符,通常用于直接从配置文件(如application.yml
或application.properties
)中读取配置。 -
@Value("#{...}")
:用于Spring Expression Language (SpEL) 表达式,支持更多的逻辑运算,比如计算、条件判断、Bean 属性注入等。
通俗来说:
- “$” 用来直接获取配置文件中的内容,是“配置读取”。
- “#” 则是让你写 SpEL 表达式,可以做更复杂的运算,是“表达式求值”。
二、@Value("${...}"):从配置文件直接读取属性值
@Value("${...}")
最常见的用途就是直接从配置文件中读取配置信息。你可以用它来获取基本的配置项,比如数据库连接信息、API 密钥等等。它相当于是一个占位符,帮我们把写在配置文件里的值直接注入到代码中。
代码示例
假设我们在 application.yml
文件中定义了以下内容:
app:
name: MyCoolApp
version: 1.0.0
我们可以这样直接使用 @Value("${...}")
注解:
@Component
public class AppConfig {
@Value("${app.name}")
private String appName;
@Value("${app.version}")
private String appVersion;
public void printConfig() {
System.out.println("应用名称: " + appName);
System.out.println("应用版本: " + appVersion);
}
}
运行结果:
应用名称: MyCoolApp
应用版本: 1.0.0
这种方式非常直接,就是把 application.yml
或 application.properties
中的值注入进来。
适用场景:
- 读取简单的属性值,比如应用名称、版本号、数据库连接地址等。
- 读取不需要复杂运算的配置项。
三、@Value("#{...}"):动态计算和注入
@Value("#{...}")
则是更强大的工具。它支持 SpEL 表达式,允许我们在注解中进行逻辑运算、方法调用、甚至 Bean 注入。这对于需要动态计算的场景非常适用,比如根据环境变量决定某个配置值,或者在配置时做简单的逻辑判断。
代码示例 1:运算
@Component
public class CalculationService {
@Value("#{10 * 5}")
private int calculatedValue;
public void printValue() {
System.out.println("计算值: " + calculatedValue);
}
}
运行结果:
计算值: 50
这个例子中,我们直接在 @Value
中进行了乘法运算,将结果注入到 calculatedValue
中。
代码示例 2:调用其他 Bean 的属性
@Component
public class ConfigService {
@Value("#{appConfig.appName + ' v' + appConfig.appVersion}")
private String fullAppName;
public void printFullAppName() {
System.out.println("完整应用名称: " + fullAppName);
}
}
这里我们用 @Value("#{...}")
从另一个 Bean(假设 appConfig
)中获取 appName
和 appVersion
,并动态拼接。
四、@Value("${...}") 和 @Value("#{...}") 的对比
特性 | @Value("${...}") |
@Value("#{...}") |
---|---|---|
功能 | 读取配置文件中的属性 | 支持动态计算、逻辑运算、调用方法等 |
用途 | 获取简单配置项 | 复杂计算和 Bean 引用 |
示例 | @Value("${app.name}") |
@Value("#{10 + 5}") |
五、混合使用的场景:把配置与逻辑结合
在某些情况下,我们需要同时使用配置和动态逻辑,比如在配置中读一个数值,接着对它进行简单计算。比如我们想要从配置文件中读取一个数值,然后在 @Value("#{...}")
表达式中进行计算:
# application.yml
app:
basePrice: 100
@Component
public class PriceService {
@Value("#{${app.basePrice} * 1.2}")
private double finalPrice;
public void printFinalPrice() {
System.out.println("最终价格: " + finalPrice);
}
}
运行结果:
最终价格: 120.0
这里我们先用 $
符号从配置中读取 app.basePrice
,然后用 #
符号对值进行运算。这种组合方式非常灵活,可以将配置和逻辑结合起来。
六、用错会怎样?
在项目中,我们如果不小心用错了 $
和 #
,就会发生意料之外的错误:
- 用
$
读取非配置的内容会报错,因为它只能处理简单配置; - 用
#
读取配置项会造成表达式解析失败,从而导致应用无法启动。
总结:@Value 的两种符号用法
-
@Value("${...}")
:专注于读取配置项,是直接从application.yml
或application.properties
中拿值。 -
@Value("#{...}")
:基于 SpEL 表达式,可以进行复杂的逻辑运算、Bean 注入等操作。
在实际开发中,如果只是读取简单配置,选择 ${...}
就好;如果需要动态计算、引用其他 Bean 或逻辑判断,使用 #{...}
是更佳选择。掌握了这两种写法的区别后,配置和代码管理都能变得更加灵活和高效!