SpEL通过#{...}在Spring注解中动态取值,支持@Value、@ConditionalOnExpression等注解,可访问系统属性、环境变量、Bean及参数,用于配置注入、条件加载、缓存键生成等,但仅限Spring原生支持场景且不可执行I/O或复杂逻辑。

SpEL(Spring Expression Language)可以在 Spring 的注解中通过 #{...} 语法动态取值,核心是让 Spring 容器在运行时解析表达式并注入结果。关键在于目标注解必须支持 SpEL(如 @Value、@Scheduled、@Cacheable、@ConditionalOnExpression 等),且上下文需能访问到所需对象(如配置属性、Bean、系统环境等)。
使用 @Value 注入动态配置值
这是最常见场景,从 application.properties 或环境变量中读取并做简单运算或默认值处理:
-
@Value("#{systemProperties['os.name']}")→ 获取操作系统名称 -
@Value("#{systemEnvironment['HOME'] ?: 'unknown'}")→ 获取 HOME 环境变量,为空则用默认值 -
@Value("#{${app.timeout:30} * 1000}")→ 将配置项转为毫秒(支持占位符嵌套 SpEL) -
@Value("#{T(java.lang.Math).random() > 0.5 ? 'A' : 'B'}")→ 执行简单逻辑判断
在条件注解中动态控制 Bean 加载
配合 @ConditionalOnExpression 实现运行时条件判断:
-
@ConditionalOnExpression("#{environment.getProperty('app.feature.enabled', 'false').equals('true')}")→ 根据配置开关决定是否创建 Bean -
@ConditionalOnExpression("#{systemProperties['java.version'].startsWith('17')}")→ 按 JDK 版本条件化加载
在缓存与异步注解中动态生成键或参数
例如 @Cacheable 的 key 属性、@Async 的 value(指定线程池名)都支持 SpEL:
立即学习“Java免费学习笔记(深入)”;
-
@Cacheable(value = "userCache", key = "#userId + '_' + #type")→ 组合参数生成缓存键 -
@Cacheable(key = "#p0.name + #p1")→ 使用位置参数(#p0 是第一个参数对象,#p1 是第二个) -
@Async("#{@taskExecutorMap[environment.getProperty('app.async.pool', 'default')]}")→ 动态选择线程池 Bean
注意事项和常见问题
SpEL 在注解中不是万能的,有明确限制:
- 仅支持 Spring 原生支持 SpEL 的注解;自定义注解需自行解析,不能直接用
#{...} - 表达式中可访问:系统属性(
systemProperties)、环境变量(systemEnvironment)、Spring Environment(environment)、Spring Bean(用@beanName)、方法参数(#paramName或#p0)、字面量和基本运算 - 不能调用任意 Java 方法(除非是静态方法,用
T(...)引用),也不能执行复杂业务逻辑或 I/O 操作 - 若表达式解析失败(如属性不存在、类型不匹配),启动会报错(
BeanCreationException),建议配合默认值(?:)或合理配置校验


















