在系统测试的过程中,测试说有个功能报错,可是我们在本地测试都没有问题,报错如下:

10:35:39.193 [http-nio-18070-exec-70] ERROR c.a.f.w.e.GlobalExceptionHandler - [handleException,80] - 请求地址'/business/asset/export/detail',发生系统异常.org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.NoSuchMethodError: cn.hutool.core.bean.BeanUtil.setFieldValue(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1082)at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)at javax.servlet.http.HttpServlet.service(HttpServlet.java:665)at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)at javax.servlet.http.HttpServlet.service(HttpServlet.java:750)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:111)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:111)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:124)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)at com.assetmanage.common.filter.RepeatableFilter.doFilter(RepeatableFilter.java:39)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:327)at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115)at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122)at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126)at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)at com.assetmanage.framework.security.filter.JwtAuthenticationTokenFilter.doFilterInternal(JwtAuthenticationTokenFilter.java:42)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:111)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110)at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211)at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183)at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354)at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360)at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:889)at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1743)at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)at java.lang.Thread.run(Thread.java:750)Caused by: java.lang.NoSuchMethodError: cn.hutool.core.bean.BeanUtil.setFieldValue(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;at com.assetmanage.business.service.impl.TAssetServiceImpl.lambda$selectAssetTypeDetailExportList$0(TAssetServiceImpl.java:1295)at java.util.ArrayList.forEach(ArrayList.java:1259)at com.assetmanage.business.service.impl.TAssetServiceImpl.selectAssetTypeDetailExportList(TAssetServiceImpl.java:1290)at com.assetmanage.business.service.impl.TAssetServiceImpl$$FastClassBySpringCGLIB$$9ada384c.invoke(<generated>)at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:783)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:58)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388)at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:698)at com.assetmanage.business.service.impl.TAssetServiceImpl$$EnhancerBySpringCGLIB$$19e5338.selectAssetTypeDetailExportList(<generated>)at com.assetmanage.web.controller.business.TAssetController.exportTypeDetail(TAssetController.java:81)at com.assetmanage.web.controller.business.TAssetController$$FastClassBySpringCGLIB$$b64dbe74.invoke(<generated>)at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:783)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:698)at com.assetmanage.web.controller.business.TAssetController$$EnhancerBySpringCGLIB$$f1a1d7d3.exportTypeDetail(<generated>)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)... 94 common frames omitted

看到异常后我们来解读一下这个异常:

日志头部:

  • 10:35:39.193 [http-nio-18070-exec-70] ERROR c.a.f.w.e.GlobalExceptionHandler:这表示在上午10点35分39秒,应用程序中的一个全局异常处理器(GlobalExceptionHandler)捕获了一个错误。http-nio-18070-exec-70 是线程的名称,表明这是在处理HTTP请求时发生的。

错误描述:

  • 请求地址'/business/asset/export/detail',发生系统异常.:这表明异常发生在处理URL为 /business/asset/export/detail 的请求时。

异常类型:

  • org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.NoSuchMethodError: 这说明异常是由于在Spring的servlet处理中存在一个未找到方法的问题(NoSuchMethodError),这通常表示代码试图调用一个不存在的方法。

具体异常原因:

  • java.lang.NoSuchMethodError: cn.hutool.core.bean.BeanUtil.setFieldValue(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;:这是异常的核心,表明调用hutool库中的BeanUtil.setFieldValue方法时发生了错误,因为该方法不存在或者方法签名与调用不匹配。

异常发生的位置:

  • 异常发生在com.assetmanage.business.service.impl.TAssetServiceImpl.lambda$selectAssetTypeDetailExportList$0(TAssetServiceImpl.java:1295):这表明错误发生在TAssetServiceImpl类的selectAssetTypeDetailExportList方法内,具体在文件的第1295行。

  • public List<AssetTypeDetailExportVo> selectAssetTypeDetailExportList(AssetListQueryParam param) {List<AssetExportVo> assetExportVos = tAssetMapper.selectAssetExportList(param);List<AssetTypeDetailExportVo> exportVos = BeanUtil.copyToList(assetExportVos, AssetTypeDetailExportVo.class);exportVos.forEach(vo ->{if (StringUtils.isNotBlank(vo.getTypeName())) {String[] types = vo.getTypeName().split("/");String fieldName = "typeName";for (int i = 0; i < types.length; i++) {BeanUtil.setFieldValue(vo, fieldName + (i + 1), types[i]); // TAssetServiceImpl中1295行代码}}});return exportVos;}

调用栈追踪:

  • 接下来的部分是调用栈的追踪,详细列出了异常发生时的方法调用序列。这可以帮助开发者理解异常发生时程序的状态和调用路径。

涉及的技术:

  • 从日志中可以看出涉及到的技术包括Spring Framework、Tomcat服务器、Spring Security等。

结论:

此错误通常是由于在编译时引用的库在运行时不可用或版本不匹配所致。由于在TAssetServiceImpl.java1295行执行了BeanUtil.setFieldValue()方法,所以这个错误很可能是hutool不兼容或使用了错误的版本有关。解决这类问题通常需要确保所有环境中使用的库版本一致,并且没有其他冲突的依赖。

解决方法:

通过上述总结,可以得到是系统中很可能有两个不同版本的hutool依赖,因此我排查后发现确实引用了两个不同版本的依赖:

<!----><!--cn.hutool--><!--hutool-core--><!--5.7.20--><!----><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.16</version></dependency>

由于hutool-all中是包含了hutool-core,所以我把hutool-core注释了,问题也因此解决。

总结:

这个错误通常体现为本地执行某个业务时不会报错,但是部署到linux系统后因为环境差异,类加载顺序不同可能会发生该问题,通过排查和分析,确定了问题源自于hutool库的不同版本依赖。解决方法是移除了较老版本的hutool-core依赖,仅保留了hutool-all,这样可以确保项目中hutool的功能和API的一致性。

在编写或维护代码时,我们可能会遇到各种运行时错误,尤其是在不同环境之间迁移代码时。这个案例就是一个典型的例子,它突显了库依赖管理的重要性以及如何处理兼容性问题。