jar包版本不一致带来的NoSuchMethodError错误

267 阅读2分钟

bug描述

为了方便观察方法优化前后的执行时间,我使用自定义注解,配合AOP和StopWatch用来计算执行时长,但是运行项目时出现了异常信息:Handler dispatch failed: java.lang.NoSuchMethodError: 'double org.springframework.util.StopWatch......'

我的代码如下,其中StopWatch使用的是org.springframework.util包下的类,报错信息却是找不到这个方法

自定义注解

@Target(ElementType.METHOD)  
@Retention(RetentionPolicy.RUNTIME)  
public @interface CostTime {  
}

切面类(这里贴的是修改后的代码)

@Aspect  
@Slf4j  
@Component  
public class CostTimeAspect {  
    @Pointcut("@annotation(com.tomla.gomall.aop.annotations.CostTime)")  
    public void CostTime(){}  
     
    @Around("CostTime()")  
    public Object costTime(ProceedingJoinPoint point) throws Throwable {  
        StopWatch stopWatch = new StopWatch();  
        stopWatch.start();  
        //执行切入点,获取返回值  
        Object proceed = point.proceed();  
        //方法名  
        String methodName = point.getSignature().getName();  
        //类名  
        String className = point.getSignature().getDeclaringTypeName();  
        //计算耗时  
        stopWatch.stop();  
        log.info("类:{},方法:{},执行耗时(毫秒):{}",className,methodName,stopWatch.getTotalTimeMillis());  
        return proceed;  
    }  
}

在需要统计执行时长的方法上加注解@CostTime

@CostTime  
@GetMapping("/detail/{skuId}")  
public Result<SkuItemVo> getDetailBySkuId(@PathVariable("skuId") Long skuId){  
    return skuInfoService.getDetailBySkuId(skuId);
}

解决bug

  • 网上查阅资料可知,引起这个问题有多种原因,包括 jdk版本不同依赖了不同版本jar包等等。我突然意识到我所用的StopWatchorg.springframework.util包下的,这个包位于spring-core包下,而我把这个基于自定义注解的切面类写在了微服务的common模块下,在其他服务中使用了这个自定义注解。也就是说,我定义切面类与使用切面类的位置不同,而两者使用的spring-core依赖版本不同!common模块使用的是org.springframework:spring-core:6.1.1版本,而另一个服务使用的是org.springframework:spring-core:6.0.4版本,意味着编译与运行时所处的环境不同,造成了这个严重的bug。
  • 解决办法一:由于common引入了hutool工具包,而其他服务都用到了此工具,所以统一使用hutool中提供StopWatch工具类,这样就不会出现使用了不同jar包带来的 NoSuchMethodError 问题了。
  • 解决方法二:将两个模块中的spring-core修改为同一版本,不过我更喜欢第一种解决办法。

总结:亲测两种方案都可以解决这个bug。既然使用了hutool,就尽量使用它提供的工具类,多个服务共用,避免了jar包版本不一致的问题。