分享一个使用IDEA+Spring Boot框架开发的隐性问题

大家好,我是杰哥

最近在项目中遇到一个特别奇怪的问题:程序中定时同步数据的操作,执行单元测试可以成功执行,直接启动主程序却无法正常执行(Spring Boot框架、java语言,IDEA开发,采用junit测试框架)

猜测

之前没有遇到过类似问题。根据这个现象,猜测是两者启动应该有什么参数的不同,或者是加载的类不同或者加载顺序有区别导致的。但是理论上来说,两者在启动过程中,Spring 所加载的东西又似乎没有什么区别呀,所以刚开始是有一点摸不着头脑的

对比不同之处

于是便试着开始问题的一步步排查过程

对于看起来比较奇怪的问题,之前文章中提到过,有一个比较高效的问题排查方法:若存在正确的情况,包括对于偶发性的问题的成功场景,以及不同的运行方式产生正确的结果等,我们可以通过对比产生问题的方案与正确场景的不同之处,通过不同之处入手,进行问题原因的定位分析

初步进展

对同步方法:save() 方法,进行 debug 方式定位

但进入了不知道多少层的调用,也没有发发现问题何在。只是发现:主程序启动的时候,执行了一次 save() 方法方法,以后就再也不执行了;而单元测试则每次都可以正常执行

日志打印

save() 方法执行时,捕获异常,打印异常日志,并打印成功日志

try{
    save(data);
}catch(Exception e){
    log.error("执行失败,{}",e.getMessage());
}
    log.info("执行成功:{}",data);

复制代码

结果,并没有任何日志打印。没有失败日志,也没有成功日志。那就是说明,主程序在启动过程中,在第一次执行save方法时,便出现了异常

但是具体出现了什么异常,暂时还无从得知

一、调整日志级别

具体出现了什么异常呢?默认的日志级别是 info ,应该是没有看到打印出来的异常信息吧,于是我将日志级别调整至 debug

#slf4j设置日志级别
logging.level.root=debug
复制代码

首先启动单元测试,发现基本没有什么多余的报错日志

然后启动主程序,发现的确多了一个报错,而且在不断打印,应该是不断重试的效果

javax.management.InstanceNotFoundException: org.springframework.boot:type=Admin,name=SpringApplication
复制代码

因为没其他辙,所以就直接以这个报错为突破口来分析了

二、分析现象

先来分析一波:

日志提示找不到 Spring Boot 的主类:SpringApplication

那就说明是有什么东西在 Spring Boot 还没有完成类的初始化、自动装配等动作时,就已经想要去加载 Spring Boot

顺着这个猜测,脑袋里突然冒出一个大胆的想法,就是启动参数配置有差别导致的

于是乎,分别看了下 IDEA 对于主程序单元测试的启动参数配置是否有何不同

1、单元测试的启动配置

image.png

2、主程序的启动配置

image.png

可以看到,主程序启动比单元测试的启动默认是多了两项配置的,这也许就是问题的原因所在!

当前,对于我们最初的这个问题,目前发现两者的

三、问题解决

于是,采用如下解决步骤:

1) 在IDEA工具栏选择Run,在打开的列表中选中 Edit Configurations

image.png

2) 打开的面板左侧 Spring Boot 下选择需要运行的 Application

3) 去掉右侧 Enable launch optimizationEnable JMX agent 的勾选

4) 重启服务即可!

try{
    save(data);
}catch(Exception e){
    log.error("执行失败,{}",e.getMessage());
}
    log.info("执行成功:{}",data);

复制代码

重启服务,发现那个错误已经不存在了,而 save() 方法执行结束之后

打印出了执行成功的日志

啊哈,那么就是说,问题就这样完美解决了

目前来看,问题的原因在于:开启了启动优化和 JMX 的代理功能之后,他们会在Spring Boot 完全启动之前就去加载 Spring Boot,顺序发生变化导致某些类或者配置无法正常加载导致的

而关掉了这两项配置,则成功解决问题!

四、总结

好了,问题是不难,问题的最根本原因其实也没有真正查出来,但是也算是多了一个比较奇怪的知识

回顾一下我们解决它的方式,猜测、定位、猜测、日志级别调整、分析、确认

1)先通过表面的现象来寻找具体的现象save() 方法只进入了一次,并且在方法执行过程中出现问题

2)再考虑可能是什么原因导致这样的问题,猜测可能是过程中出现了问题。但是没有打印日志,换句话说,就是打印了日志,在当前的日志级别中无法看到

3)那么,就调低日志的级别,试着对比两者启动时日志的打印区别

还算顺利,我们调整到 debug 级别日志以后,立刻发现了其不同之处:使用主程序启动时,多打印了一个异常的堆栈信息,然后问题原因就落在了这个异常信息中

4)转向另一个明显问题的解决

通过解决这个异常,也就解决了问题本身

分享这个问题,主要是记录一下使用 IDEA 进行 Spring Boot 框架java 程序开发,会存在默认启动参数配置而导致奇怪问题出现的坑(当然其他框架或者使用编辑器可能也会存在类似问题);也想要分享给大家,遇到类似问题的一种解决方案,避免浪费太多宝贵时间

还有一点,就是想要再次强调一下日志打印级别掌握的重要性,工作中的确是可以通过 debug 的方式快速定位问题出现的地方,但是前提是你特别清楚了当前程序的执行过程和执行逻辑

当程序较为复杂时,通过调整日志级别来定位问题的效率还是更高一些的

嗯,就这样。每天学习一点,时间会见证你的强大~

欢迎大家关注们的公众号,一起持续性学习吧~

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享