Spring ${} vs #{} 语法全景图
一句话记忆:
${} 是 占位符 (静态字符串替换),#{} 是 SpEL 表达式 (运行时计算)。二者可以 嵌套 、联动 ,带来 声明式动态能力。
一、基础区别
| 维度 | ${} | #{} | 
|---|---|---|
| 名称 | Property Placeholder | SpEL(Spring Expression Language) | 
| 求值时机 | 容器启动时 替换 | 运行时 解析 | 
| 数据来源 | Environment、PropertySource | Bean、系统属性、运算、方法调用 | 
| 常见用途 | 读取 application.yml | 计算、条件、集合、Bean 调用 | 
| 示例 | ${server.port} | #{T(java.lang.Math).random()} | 
| 默认值 | ${key:default} | #{key ?: default} | 
二、基础用法对比
1️⃣ 读取配置
            
            
              yaml
              
              
            
          
          my:
  name: Tom
  age: 18
            
            
              java
              
              
            
          
          @Value("${my.name}")           // Tom
private String name;
@Value("${my.age}")            // 18(字符串)
private int age;
@Value("${unknown:default}")   // default
private String fallback;2️⃣ 运行时计算
            
            
              java
              
              
            
          
          @Value("#{T(java.lang.Math).random() * 100}")
private double rand100;
@Value("#{systemProperties['os.name']}")
private String os;三、混合嵌套(经典技巧)
            
            
              java
              
              
            
          
          @Value("#{${feature.price} * (1 + ${feature.tax})}")
private BigDecimal finalPrice;- ${feature.price}先被替换为- 100,表达式变为- #{100 * (1 + 0.2)}→- 120。
四、高级用法速查表
| 场景 | 代码示例 | 
|---|---|
| 三目/Elvis | "#{flag ? 'A' : 'B'}"/"#{name ?: 'NO_NAME'}" | 
| 集合索引 | "${list[0]}"/"#{map['key']}" | 
| 集合过滤 & 投影 | "#{users.?[age > 18].![name]}" | 
| 正则匹配 | "#{email matches '^[\\w\\.-]+@(.+)$'}" | 
| Bean 调用 | "#{priceService.current() * 1.1}" | 
| 静态方法 | "#{T(java.time.LocalDate).now()}" | 
| 条件 Bean 注册 | @ConditionalOnExpression("#{env['spring.profiles.active'] == 'prod'}") | 
五、XML / 注解 / 编程式 全场景
| 场景 | 写法 | 
|---|---|
| XML | <property name="timeout" value="#{${timeout} * 1000}"/> | 
| @Bean | @Bean @ConditionalOnExpression("#{systemProperties['debug'] != null}") | 
| 编程式 | ExpressionParser parser = new SpelExpressionParser(); | 
六、常见误区 & 避坑
| 坑 | 说明 | 
|---|---|
| ${}不支持运算 | ${1+2}会原样输出,不会被计算 | 
| #{}在 application.yml 无效 | 只能在 @Value、XML、@Conditional等场景使用 | 
| 构造器注入 无法实时刷新 | 使用 @ConfigurationProperties或字段注入 | 
| 默认值写法 | ${key:default}vs#{key ?: default} | 
七、一句话总结
${} 负责"占位",#{} 负责"计算";
二者嵌套即可实现声明式动态配置,让 Spring 在运行时依旧"活"起来。