Spring 中 @Value 竟有“$”和“#”两种写法?看完才明白区别有多大!

image.png

如果你和我一样,曾经被 Spring 中 @Value 注解中的“”和“#”符号搞得有点迷糊,那今天我们就来好好捋一捋。虽然平时开发中我们经常直接写 `@Value("{property.key}")来获取配置,但有些场景下突然需要使用#`,不禁让人疑惑:这两者究竟差别在哪儿?用错了会有什么后果?

下面就带大家一起深入了解 @Value("${...}")@Value("#{...}") 的区别,并用简单易懂的例子来解释各自的应用场景。


一、“$” 和 “#” 的区别:属性值 vs. SpEL 表达式

在 Spring 中,@Value 注解支持两种主要语法:

  • @Value("${...}"):用于属性值的占位符,通常用于直接从配置文件(如 application.ymlapplication.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.ymlapplication.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)中获取 appNameappVersion,并动态拼接。

四、@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.ymlapplication.properties 中拿值。
  • @Value("#{...}"):基于 SpEL 表达式,可以进行复杂的逻辑运算、Bean 注入等操作。

在实际开发中,如果只是读取简单配置,选择 ${...} 就好;如果需要动态计算、引用其他 Bean 或逻辑判断,使用 #{...} 是更佳选择。掌握了这两种写法的区别后,配置和代码管理都能变得更加灵活和高效!

推荐阅读文章

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容