凌晨两点,支付服务的告警像雪崩一样砸来,你在控制台和栈跟踪间疯狂穿梭,却始终想不明白:Spring 的依赖注入,怎么会在生产里突然“失手”?我最近读到一篇事故复盘,讲的是两个看似无害的改动如何在生产环境联手把系统击穿,分析深入、启发很大。于是我把它完整翻译出来,分享给大家,希望能帮你少走弯路。
以下内容翻译自:https://medium.com/javarevisited/the-autowired-bug-that-cost-us-3-days-7d24a1e31435
两个“看似无害”的 PR 如何在凌晨 2 点联手击碎生产环境的依赖注入。
我们的首席架构师在一个构造器上加了 @Autowired,应用能编译。测试通过。代码评审也过了。
然后凌晨两点,生产炸了,NullPointerException 到处都是。
故事从一次“简单”的重构开始
如果你曾在周五合并过一个“很安全”的重构,你大概知道故事怎么发展。
我们在支付服务里清理技术债。没啥花哨的——把一个巨型类拆成更小、更可测的组件而已。- @Service
- public class PaymentProcessor {
-
- @Autowired
- private PaymentGateway gateway;
-
- @Autowired
- private FraudDetector fraudDetector;
-
- @Autowired
- private NotificationService notificationService;
-
- // 847 行业务逻辑...
- }
复制代码 我们的架构师,就叫他 Dave,决定改用构造器注入。“最佳实践”,他说。干净、不可变、易测试。
听起来很合理,对吧?- @Service
- public class PaymentProcessor {
-
- private final PaymentGateway gateway;
- private final FraudDetector fraudDetector;
- private final NotificationService notificationService;
-
- @Autowired
- public PaymentProcessor(
- PaymentGateway gateway,
- FraudDetector fraudDetector,
- NotificationService notificationService
- ) {
- this.gateway = gateway;
- this.fraudDetector = fraudDetector;
- this.notificationService = notificationService;
- }
-
- // 业务逻辑...
- }
复制代码 完美。final 字段、构造器注入,跟每篇 Spring Boot 教程教的一样。
周四发版。周五风平浪静。周末也很安稳。
周一清晨,地狱之门打开。
凌晨两点:一切开始崩坏
我们 Slack 的 #incidents 频道像圣诞树一样亮了起来。
[code]PagerDuty:
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |