You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Java中解析Spring占位符,模拟@Value注解功能

在Java代码中实现@Value注解的功能

我之前也踩过这个坑,用SpelExpressionParser和Environment没成功多半是没把两者的逻辑结合对——毕竟@Value的底层就是先解析${}格式的环境占位符,再处理#{}包裹的SpEL表达式。下面给你一套可行的实现方案:

核心思路

@Value的工作流程分两步:

  1. 先替换${property.name}这类占位符,从Spring环境(Environment)中读取对应属性值
  2. 再解析剩余的#{spel.expression}部分,执行SpEL表达式计算结果

咱们就按照这个流程来写代码,用Spring的公开API完成复刻。

完整实现代码

首先创建一个组件类,注入Environment并封装解析逻辑:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.expression.StandardEvaluationContext;
import org.springframework.core.env.Environment;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.TemplateParserContext;
import org.springframework.stereotype.Component;

@Component
public class ManualValueResolver {

    private final Environment environment;
    private final ExpressionParser spelParser;
    private final TemplateParserContext templateContext;

    // 用构造注入保证Environment已初始化
    @Autowired
    public ManualValueResolver(Environment environment) {
        this.environment = environment;
        this.spelParser = new SpelExpressionParser();
        // TemplateParserContext专门用来解析"xxx #{expr} yyy"这种模板式SpEL
        this.templateContext = new TemplateParserContext();
    }

    public String resolveValue(String expression) {
        // 第一步:解析${}占位符,从环境中获取属性值
        String resolvedPlaceholders = environment.resolveRequiredPlaceholders(expression);
        
        // 第二步:解析#{}格式的SpEL表达式,把Environment作为根对象方便SpEL访问环境属性
        return spelParser.parseExpression(resolvedPlaceholders, templateContext)
                .getValue(new StandardEvaluationContext(environment), String.class);
    }
}

使用示例

假设你的application.properties里有app.name=MySpringApp,调用这个方法:

// 注入咱们写的解析器
@Autowired
private ManualValueResolver valueResolver;

public void testResolver() {
    String result = valueResolver.resolveValue("应用名称:${app.name},当前时间:#{T(java.time.LocalDateTime).now()}");
    System.out.println(result);
    // 输出类似:应用名称:MySpringApp,当前时间:2024-05-20T14:30:00.123
}

常见问题排查

如果之前尝试失败,可能是这几个原因:

  • 没有用TemplateParserContext:默认的SpEL解析器只能处理纯表达式(比如直接写T(java.time.LocalDate).now()),无法解析带#{}包裹的模板字符串
  • 没先解析${}占位符:直接用SpEL解析包含${}的字符串会报错,因为SpEL不认识这种格式
  • 初始化时机不对:在Spring容器完全启动前调用解析逻辑,Environment还没加载完属性

内容的提问来源于stack exchange,提问作者Bill

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:25:02