摘要:上个月我去面试一家AI初创公司,对方面试官是个大胡子的中年大哥,眼神犀利,一上来寒暄几句之后就抛来一个问题:
先讲个小故事。
上个月我去面试一家AI初创公司,对方面试官是个大胡子的中年大哥,眼神犀利,一上来寒暄几句之后就抛来一个问题:
“你可以在Spring中注入一个 null 吗?或者注入一个空字符串呢?”
???
我当时脑袋一懵。
“这啥鬼问题,太简单了吧?”我心里想着,“当然可以啊,只要给个配置就好。”但我隐隐感觉有点不对劲,于是我开始结结巴巴地分析起来,什么默认值啦、@Value啦、Bean注入啦,整了个大概三分钟的回答。
大哥微微一笑,说:
“你说的不是错,但还是太表面了。你真的知道 Spring 是怎么处理这些注入的吗?”
……
那一刻,我知道,我掉坑里了。
于是,我决定回家把这问题彻底研究透。今天就跟大家一起复盘这个“看似简单但细思极恐”的问题。
这是一道典型的“你以为你懂,其实不懂”的面试题。
我们来把问题拆解一下:
能不能通过 Spring 注入一个 null?能不能通过 Spring 注入一个空字符串?注入方式不同,结果是否会不同?@Value 注入 vs @Autowired 注入 vs XML配置,有差别吗?我们一个个来,搞清楚这事。
1. 配置文件注入 null —— 行不通!
如果你用这种写法:
然后代码里这样注入:
你猜 myValue 是 null 吗?
并不是!它是字符串 "null"!
因为在 application.properties 文件中,没有“真正的 null”这个概念,Spring 会把你写的 null 当成字符串 "null" 处理。也就是说你以为你注入了 null,实际上你注入了四个字符:n、u、l、l。
【小米吐槽】:这个是我第一次翻车的地方,我当时还信誓旦旦地说“@Value 可以注入 null”,现在想想,真是年轻……
2. @Value 注入 null 的“正确姿势”
想要真正注入 null,有两种方式:
方法一:使用 SpEL 表达式
这才是真正注入了一个 null!
Spring Expression Language(SpEL)是个宝藏,#{} 里的表达式是直接求值的,#{null} 的返回值就是 Java 中的 null。
方法二:使用条件判断返回 null
你甚至可以写 SpEL 表达式判断某个条件是否满足,不满足就返回 null:
或者:
这两种方式都可以让 Spring 把 my.value 解析为 空字符串。
然后:
此时 myValue 就真的是 "",也就是 Java 字符串中的空内容。
注意:Spring 不会把空字符串转换为 null,除非你用特殊处理。
现在我们换个场景,用 @Autowired 来注入 Bean,看能不能注入 null。
这时候,如果 Spring 容器里没有 OtherService 这个 Bean,会发生什么?
默认情况下,Spring 会抛出异常!
因为 @Autowired 默认是 required=true,容器找不到依赖就会报错。但如果你设置了:
那就可以了!otherService 会是 null,Spring 不会抛异常。
所以,@Autowired(required = false) 是实现 null 注入的关键方式之一。
1. null != “null”
记住,字符串 "null" 和真正的 null 是完全不同的。
你在配置文件写:
结果你代码里拿到的是 "null",不是 null!
面试官很喜欢问这个陷阱问题。
2. @Value 默认值无法为 null?
Spring 提供了这种写法:
你想写成:
这不是 null,而是字符串 "null"。
想要默认值为 null,唯一办法就是 SpEL:
在 Spring 中,如果使用 @Value 注入属性时,直接配置为 null 是无法得到真正的 null 的,反而会变成字符串 "null"。如果想注入真正的 null,应该使用 SpEL 表达式 @Value("#{null}")。而空字符串是可以通过配置文件正常注入的,比如 key= 或 key="" 都可以。
此外,如果使用 @Autowired 注入 Bean,默认是 required 的,容器中找不到 Bean 会报错。如果设置 required = false,那么没有 Bean 时字段会被注入 null。
你可以补充一句:
实际项目中很少主动注入 null,因为这违背了依赖注入的“确定性”原则,除非你明确需要。
面试官大概率点头+加分!
你可能会问:“小米,这些东西真的用得到吗?”
当然用得上!
比如说我们做配置中心(Apollo、Nacos等)动态配置的时候,某些参数的“未设置状态”需要用 null 表示。这时候注入一个默认 null 就很有必要。
再比如你做权限判断、策略切换等,某些 Bean 是可选的,通过 @Autowired(required = false) 注入,就能灵活控制逻辑分支。
有时候问题不在于你知道多少,而在于你能不能从基础问题里悟出原理、看出本质。
Spring 很强大,但它也是有规则有边界的,我们理解这些规则,才能在实战中游刃有余。
如果你觉得这篇文章对你有帮助,欢迎点赞、在看、转发给你的面试群!
来源:苍客公考考试