spring #{} 与 ${} 区别

${}#{} 的核心区别

特性 ${} #{}
名称 属性占位符 SpEL表达式
解析时机 启动时/类加载时 运行时
执行引擎 Spring属性解析器 Spring表达式语言(SpEL)
主要用途 读取配置文件 执行表达式/方法调用
动态计算 静态值替换 动态计算
默认值 支持 ${key:default} 需要在内部使用${}

1. ${} - 属性占位符

功能:从Spring Environment、properties文件、YAML文件中读取配置值

java 复制代码
@Component
@RocketMQMessageListener(
    topic = "${rocketmq.topic}",           // 从配置文件读取
    consumerGroup = "${rocketmq.group:default-group}" // 带默认值
)

YAML配置:

bash 复制代码
rocketmq:
  topic: test-topic
  group: test-group

特点:

  • ✅ 只能做静态值替换

  • ✅ 支持默认值 ${key:default}

  • ✅ 不支持运算、方法调用

  • ✅ 解析发生在依赖注入阶段


2. #{} - SpEL表达式

功能:执行Java代码、调用方法、访问Bean属性、进行运算

java 复制代码
@Component
@RocketMQMessageListener(
    // 调用Bean的方法
    topic = "#{@topicConfig.getTopic()}",
    
    // 访问Bean属性
    consumerGroup = "#{@consumerProperties.group}",
    
    // 三目运算符
    selectorExpression = "#{@config.env == 'prod' ? 'tag1' : 'tag2'}"
)

支持的表达式:

java 复制代码
// 调用静态方法
#{T(System).currentTimeMillis()}

// 字符串操作
#{'${rocketmq.topic}'.toUpperCase()}

// 条件运算
#{@conditionService.isEnable() ? 'topicA' : 'topicB'}

// 数学运算
#{${server.port:8080} + 1}

3. 两者组合使用

java 复制代码
@Component
@RocketMQMessageListener(
    // ${} 作为 #{} 的参数
    topic = "#{'${rocketmq.topic:default}'.toUpperCase()}",
    
    // 读取配置并进行运算
    consumerGroup = "#{'group-' + '${rocketmq.group:default}'}",
    
    // 复杂逻辑
    selectorExpression = "#{@tagService.getTags('${rocketmq.biz.type}')}"
)

4. 典型应用场景对比

场景 推荐方式 示例
读取简单配置 ${} ${rocketmq.topic}
配置默认值 ${} ${rocketmq.group:default}
调用Bean方法 #{} #{@service.method()}
字符串处理 #{} #{'test'.toUpperCase()}
条件判断 #{} #{@env == 'dev' ? A : B}
访问数组/集合 #{} #{@config.list[0]}
配置文件转大写 ${} + #{} #{'${topic}'.toUpperCase()}

5. 注解中使用的限制

Spring注解中 (如@Value@RocketMQMessageListener):

  • ${} - 直接支持,自动解析配置文件

  • #{} - 需要配置spring.factories或特定版本才支持

java 复制代码
// ✅ 直接工作
@Value("${rocketmq.topic}")

// ⚠️ 部分注解不支持#{},或需要特殊处理
@RocketMQMessageListener(topic = "#{...}")  // 某些版本可能不解析

6. 最佳实践建议

简单场景:只用${}

java 复制代码
@RocketMQMessageListener(
    topic = "${rocketmq.topic}",
    consumerGroup = "${rocketmq.group}"
)

复杂场景:在#{}内嵌${}

java 复制代码
@RocketMQMessageListener(
    topic = "#{'${rocketmq.topic}'.trim()}",
    consumerGroup = "#{@environment.getProperty('rocketmq.group')}"
)

无法使用#{}时:通过中间Bean

java 复制代码
@Component
public class TopicProvider {
    @Value("${rocketmq.topic}")
    private String topic;
    
    public String getTopic() {
        return topic.toUpperCase(); // 复杂处理
    }
}

// 使用时
@RocketMQMessageListener(
    topic = "#{@topicProvider.getTopic()}"
)

总结

  • ${}:读配置,静态替换,简单直接 ✅

  • #{}:执行代码,动态计算,功能强大 ⚡

  • 组合使用#{'${key}'.method()} 最灵活 💪

相关推荐
树獭非懒10 小时前
AI大模型小白手册|Embedding 与向量数据库
后端·python·llm
唐叔在学习13 小时前
就算没有服务器,我照样能够同步数据
后端·python·程序员
曲幽15 小时前
FastAPI流式输出实战与避坑指南:让AI像人一样“边想边说”
python·ai·fastapi·web·stream·chat·async·generator·ollama
Flittly15 小时前
【从零手写 AI Agent:learn-claude-code 项目实战笔记】(1)The Agent Loop (智能体循环)
python·agent
vivo互联网技术16 小时前
ICLR2026 | 视频虚化新突破!Any-to-Bokeh 一键生成电影感连贯效果
人工智能·python·深度学习
敏编程17 小时前
一天一个Python库:virtualenv - 隔离你的Python环境,保持项目整洁
python
喝茶与编码20 小时前
Python异步并发控制:asyncio.gather 与 Semaphore 协同设计解析
后端·python
zone773920 小时前
003:RAG 入门-LangChain 读取图片数据
后端·python·面试