工作思考|研发环境好好的,怎么上线就出问题了?

场景再现

那是一个夜黑风高的晚上,某个版本迭代经过了完备的测试,正准备上线。研发同事A开完了上线评审后,信心满满地对运维同事B说:"开冲!"

几分钟后,同事B发了条消息过来,看着抖动的头像,同事A心想:小B效率真高啊,这么快!点开消息一看【启动报错了,你看一下】。

什么?启动还能报错,不可能啊,我研测环境都好好的。

小A火急火忙地连上堡垒机,看了下日志,报错信息大致为 【表tb_xxx没有找到】。

"怎么可能,我用了伟大的flyway,怎么可能会没有表呢?"小A如是说道。

提到flyway,这里简单介绍一下。Flyway是一款开源的数据库版本管理工具,可以实现管理并跟踪数据库变更,支持数据库版本自动升级,而且不需要复杂的配置,能够帮助团队更加方便、合理的管理数据库变更。只需要引入相应依赖,添加配置,再在resource目录下创建db/migration/xxxx.sql文件,在sql文件中写入用到的建表语句,插入语句即可。

不管怎么说,代码是不会骗人的。先找下是哪里出了问题!

小A很快就定位到了代码位置,是一个用于缓存的HashMap,这操作也没什么问题,相信大家都这么用过,对于一些一次查找,到处使用,还亘古不变的表信息,可以先查一次,把它用Map缓存起来,以便后续使用。

但是研发同事C把这段代码放在了afterPropertiesSet()​方法内部,没错,就是那个InitializingBean​接口的方法。看到这里,相信各位熟练背诵Bean生命周期的Java Boy已经明白了!查询数据库的操作在Bean还没有创建完成的时候就进行了!而此时,flyway脚本还没有执行,自然就找不到对应的表信息了。

那怎么办呢?

解决方法

解决方法很简单,sql执行的时候找不到表,那就让它在表创建完之后再执行!

1.CommandLineRunner接口

一个方法就是我们常用的CommandLineRunner​接口,重写run()​方法,把缓存逻辑移到run()​方法中。原因是run()方法的执行时机是在SpringBoot应用程序启动之后,此时flyway已经执行完毕,表结构已经存在,就没问题了!

2.@DependsOn注解

通过代码分析,flyway的加载是由flywayInitializer​这个Bean负责的。所以只需要我们的Bean在它之后加载就行了,这就用上了@DependsOn​注解。

@DependsOn注解可以定义在类和方法上,意思是我这个Bean要依赖于另一个Bean,也就是说被依赖的组件会比该组件先加载注册到IOC容器中。

也就是在我们的Bean上加上这么个注解@DependsOn("flywayInitializer")

总结

此次线上问题复习了Bean的生命周期,复习了InitializingBeanCommandLineRunner​两个接口,复习了@DependsOn​注解。

相关推荐
宁渡AI大模型4 分钟前
AI 全栈面试新趋势:Vibe Coding、前端、Java 后端高频面试题深度解析|河南宁渡科技有限公司编程教程
java·javascript·人工智能·python·ai大模型
CallFay云起未来14 分钟前
AI客服如何与人工客服协同?从任务路由到上下文交接的Agent架构实践
java·人工智能·文心一言
cfm_291417 分钟前
观察者模式
java
野生技术架构师37 分钟前
1000+ Java面试题知识图谱:从基础语法到分布式架构的完整拓扑
java·面试
步行cgn38 分钟前
Spring 底层如何创建对象:反射机制与实例化策略
java·后端·spring
何以解忧,唯有..1 小时前
Redis 过期事件监听:原理与实战
java
风中的小熊生气1 小时前
Spring Boot 面试知识(二):分层、IoC、异常、配置与 Redis
java·springboot
泡茶喝茶写代码1 小时前
量化数据开发实战系列(第 25 篇):基金基础接口实战:基金列表、ETF-LOF 分类、基金概况、净值数据
java·数据库·人工智能·python·mysql
shehuiyuelaiyuehao2 小时前
算法46,分治快排,排序数组
java·算法·排序算法·排序
野生技术架构师2 小时前
1200 道 JAVA 面试题(各大企业常见面试题及答案)
java·开发语言