实体类字段用 @Value 赋了默认值,取出来还是 null?

测试环境导数据,一万两千单跑到八千多行挂了。 日志里有用的一行:

复制代码
java.lang.NullPointerException

底下 at 那几行是业务包名,我不贴。 指过去的代码是这句:

java 复制代码
`String path = tmpPath + "/upload";
`

tmpPath 上面明明挂着注解:

java 复制代码
`@Value("${file.tmp.path}")
private String tmpPath;
`

我第一反应是配置漏了。 可同一个 key 在 application.yml 里躺着,测试环境那份也有, 本地单测还是绿的。

卡了半小时才看到调用方那一句:

java 复制代码
`ExcelHelper helper = new ExcelHelper();
`

就这。 我一直以为 @Value 是编译期就把值写进字段的那种注解。 实际是容器创建 bean 之后,再回头把值塞进字段。 自己 new 的对象容器根本不认识,它插不上手, 字段就停在 Java 给的初始值那一步,引用类型是 null。

我本地单测能过,是因为拿的是容器里的实例:

java 复制代码
`@Autowired
private ExcelHelper helper;
`

同一个类,两种拿法,一个有值一个没值。 Spring Boot 2.1.6,跟版本没关系,纯粹是拿对象的方式不对。

另外两种写法也常被一起提,我得分开说。

字段是 static 的,我能确定的只有一件事: 这个类压根没进容器的时候,它跟实例字段一样没人管,一直 null。 容器管的 bean 能不能把值写进静态字段我没试过, 网上那种「static 一律注不进去」的绝对话我也不太敢信。

final 那个我原本以为也是同一个坑,其实不成立。 不给初值、构造里也不赋值,它根本跑不起来,javac 先拦一道:

复制代码
FinalBlank.java:2: error: variable tmpPath not initialized
in the default constructor

编译都过不去,拿不到 null,这一种不用防。

还有一个误会挺多的:${key} 里得加冒号才算给默认值。

java 复制代码
`@Value("${file.tmp.path:}")
@Value("${file.tmp.path:/data}")
`

冒号后面留空也算给了,给的是空串。

冒号都不写、配置又真缺了,那反而好查,启动阶段直接给你:

复制代码
Could not resolve placeholder 'file.tmp.path'

进程起不来,不会拖到跑数据跑到一半。 最怕的是压根没进容器这种,一声不吭。

我原本想加一行日志自查,看类名是不是带 CGLIB 那一长串后缀。 后来发现这条路不成立:这个类身上没有任何 AOP, 容器给的实例类名也是光秃秃的,跟 new 出来的长得一样。

改成看这行日志打几次:

java 复制代码
`public ExcelHelper() {
    log.info("ExcelHelper init");
}
`

容器里是单例,整个进程就一行。 谁在 new 它,调一次刷一行,一眼就能看出来。

数据我后来重导了一遍,八千行往后那部分补上的。 tmpPath 这个坑算是填了,可测试环境那边改一次路径就得重启一次服务, 每次七八分钟起不来,这事一直挂着没人管。

相关推荐
白杨尚青1 小时前
C++入门篇(十三):vector(上)——动态数组:构造、空间增长与迭代器失效
开发语言·c++·笔记·算法·stl
杨连江1 小时前
新生儿胆红素代谢异常致细胞结晶性损伤的致死机制研究
经验分享
零基础1231 小时前
VoiceStudio 开源项目深度解析:特性、对比与实战测试
人工智能·经验分享·python·开源
做运维的阿瑞2 小时前
mysql数据库视图笔记:创建、修改、删除与适用场景
数据库·笔记·mysql
Seraphina362 小时前
DVWA(SQL Injection-High,XSS Reflected-Medium,XSS Stored-Medium)
数据库·经验分享·sql·网络安全·xss
@Mike@2 小时前
12-数据库学习笔记(五种连接算法)
数据库·笔记·学习
韩明君2 小时前
alacrity学习笔记
笔记·学习
坤坤子吖2 小时前
Python基础语法学习:函数
开发语言·笔记·python·学习
91刘仁德2 小时前
HTTPS 加密原理与 CA 数字证书:从对称加密到完整通信流程
网络·笔记·网络协议·http·https