@Value 只认容器,new 出来的对象拿不到值

发布时间:2026/10/11 10:51:16
@Value 只认容器,new 出来的对象拿不到值
这个坑是在导数据的时候撞上的。测试环境的订单表要灌数一万两千条走到八千多行程序没声了。日志里刨出来这么一行java.lang.NullPointerExceptionat 往后的帧全是业务包名我就不抄了。栈指到的代码长这样String path tmpPath /upload;tmpPath 这个字段头顶是有注解的Value(${file.tmp.path}) private String tmpPath;说实话我当时头一个念头就是配置写漏了。翻出 application.yml 一看这个 key 躺得好好的 测试环境里那份也一模一样 本地的单测也没报错。折腾了半个钟头我才盯着调用方那一行ExcelHelper helper new ExcelHelper();就这么个写法。在我原来的印象里Value 属于编译阶段就完成赋值的那类注解。事实正相反容器把 bean 造好之后才有回填这一步 把配置值写进字段。bean 这词听着玄说白了就是容器替你创建、也替你持有的对象。对象要是你自己 new 出来的容器管不着 回填这步自然没有字段维持 Java 默认初值引用类型就是 null。本地单测为什么是绿的用的实例来自容器Autowired private ExcelHelper helper;类还是同一个类只换了获取方式一边有值一边为空。版本是 Spring Boot 2.1.6这里真不怪版本 要怪就怪对象来路不对。这种实例现场有没有快办法认出来我试过看日志。思路一打一行看类名尾巴有没有 CGLIB 那串东西。 CGLIB 是 Spring 生成代理类用的工具经它手的类名会变长。这条路走死了类上没挂任何 AOP 容器发下来的实例类名干干净净和 new 出来的看不出区别。思路二数构造日志出现几次public ExcelHelper() { log.info(ExcelHelper init); }在容器里它是单例一个进程只飘一行。 谁在偷偷 new每调一次多一行谁干的立刻现形。顺带把界限划清容易混的一共有两处。先看 final我起初也把它归进同一个坑后来证伪了。既不给初值、构造函数里也不赋值编译这关就过不去 javac 会先拦下来FinalBlank.java:2: error: variable tmpPath not initialized in the default constructor连编译都过不了null 根本拿不到防它属于多余。再看 static。我只敢确定一点 类根本没被容器收管时它和实例字段一个待遇没人赋值null 到底。如果是容器里的 bean 往静态字段写值我没验过。 网上那种把 static 说成一律不可注入的绝对话我不敢全收。还有一处容易误会${key}想带默认值关键在冒号。Value(${file.tmp.path:}) Value(${file.tmp.path:/data})冒号后头什么都不写也算给了值是空字符串。要是冒号也省了、配置偏偏缺这种最好查启动直接报Could not resolve placeholder file.tmp.path进程根本起不来轮不到跑数据时才炸。 真正吓人的是没进容器那一类一点动静都不给。后来数据我重新灌了一次把八千行之后的缺口补齐。tmpPath 这一劫总算过去了。头疼的是测试环境路径改一下服务就得重启 一次七八分钟起不来到现在没人接这个活。