为什么面试要求看过源码——案例:由于spring声明周期导致的错误

有人总觉得面试造航母,工作拧螺丝钉,java初级面试中经常会问到,spring的生命周期是什么,启动之后做了哪些事情,但工作中又没关系,用不到,没有任何意义,真的是这样吗?

这里记一次只有了解spring的初始顺序才能解决的一个小问题。

问题描述

旧版本获取某数据xxx是依赖数据库的一张表tb_xxx,新版本要求获取这些数据将通过调用service_B服务的接口来获取。按理说,只是将BService的实现类中改为走接口形式即可,但改完后,发现应用无法启动!报错:Dh握手失败!我没有修改其他逻辑却无法启动,而且我调的这个接口不需要任何加密验证。作为一个入职不足两个月的本科应届毕业生遇到这种情况我是如何解决的呢?

背景介绍

应用简介
我们的java web应用service_A是动态的,页面是动态的,实体类有哪些字段也是动态的,某个实体类有哪些功能要接入哪些服务也是动态的,需要启动时读取xml配置文件决定本应用这次是什么样子,有什么能力,技术栈为SSM,为了方便自然将加载xml放在 @PostCut 中,即bean创建后来加载这些xml配置文件。

需求和变动
新版本技术栈上我们要切换至Spring Boot,同时有一些功能的变动。解析这些模型配置文件其实还依赖数据库的一张表tb_xxx,新版本要求获取这些数据将通过调用service_B服务的接口来获取。

服务调用简介
在远程调用其他服务前,需要先调用寻址服务service_X进行寻址,获得目标服务的协议、ip、端口、网域信息,然后拿到与自己服务所在网域相同的地址,然后根据指定的负载均衡的算法来获得目标服务一个可调用的实例,进行调用,敏感接口需要dh握手,数据加解密。


问题定位

我只是将一个走数据库的service方法改为了走接口,报错为Dh握手失败,没有任何改动,说明一定是这个接口调用出了问题,debug排查发现,这个DH错误是发生在服务寻址时报错的,也就是还没进入我写的代码就出错了,而服务寻址的代码是内部框架提供的,框架其他人也都在用,为什么其他人没反应?

在IDEA反编译的框架代码的寻址部分中打个断点,一步步调试发现在调用寻址服务service_X时找不到目标主机的ip端口,而框架代码中这里直接从缓存中拿的,若果没有就会抛出NPE,并被上层封装为dh错误抛出。按理说缓存中应该有寻址服务的ip端口信息。debug查看发现,这个缓存为空,size=0,说明没有放入,ctrl alt f7 查找一波,看看哪里会将秘钥对放入缓存,发现框架注入了一个Bean: ServiceInfoListener,而这个bean是在监听到ApplicationContextInitializedEvent之后执行的。

到了这里,看过spring源码或者了解spring启动时做了什么的同学瞬间就知道哪里的问题了,因为xml解析太早了,而依赖的服务寻址这时还未初始化,因此无法调用。


解决

临时方案:
将xml的解析延后至框架的监听器执行完毕后进行。

后序方案:
与框架组讨论,框架将依赖寻址服务service_X 的秘钥对配置时机提前,提前至 InitializingBean 的afterPropertiesSet时刻,即允许使用框架开发的应用在启动时进行远程远程调用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章