一次异常没有catch和Java左匹配导致的问题

问题过程

安全改造过程中,将操作日志的方法抽象成一个公共jar包,单元测试通过,上了生产也看到有日志正常输出。但第二个系统接入上生产前,测试反馈请求报500,后台有错误日志:

java.lang.NoSuchMethodError: org/apache/commons/lang/StringUtils.startsWithIgnoreCase(Ljava/lang/String;Ljava/lang/String;)Z
      at com.basicSupport.common.util.LogUtil.sensitiveOp(LogUtil.java:79)
      at com.basicSupport.common.util.LogUtil.sensitiveOp(LogUtil.java:55)
      at com.paic.sales.train.web.controller.TrainController.queryVisitPlan(TrainController.java:136)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      at java.lang.reflect.Method.invoke(Method.java:597)
      at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176)
      at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:436)
      at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:424)
      at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
      at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
      at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
      at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
      at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
      at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
      at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:301)
      at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:26)
      at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:60)
      at com.paic.sales.support.filter.DmzToWebFilter.doFilter(DmzToWebFilter.java:31)
      at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:60)
      at com.paic.sales.support.filter.EHomeLogonFilter.doFilter(EHomeLogonFilter.java:85)
      at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:60)
      at com.paic.sales.support.filter.URLThreadControlFilter.doFilter(URLThreadControlFilter.java:38)
      at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:60)
      at com.basicSupport.security.filter.BaseLimitRequestFilter.doFilter(BaseLimitRequestFilter.java:81)
      at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:60)
      at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
      at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
      at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:60)
      at com.pingan.pss.protector.ip.IpFilter.doFilter(IpFilter.java:55)
      at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:60)
      at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3748)
      at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3714)
      at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
      at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120)
      at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2283)
      at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2182)
      at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1499)
      at weblogic.work.ExecuteThread.execute(ExecuteThread.java:263)
      at weblogic.work.ExecuteThread.run(ExecuteThread.java:221)

日志指向很明显,StringUtils.startsWithIgnoreCase方法不存在,看common-lang包,2.0确实没有这个方法,升级为2.4后,恢复正常。

复盘

虽然解决,但仍有疑问:
1、自测过程日志正常输出,测试环境也有日志打印出来。
2、已接入的系统common-lang也是2.0,生产日志也是有输出的。

首先,本地也单元测试尝试复现,为保持jar包版本一致,在出错的版本中写单测

 @Test
    public void queryCustomerListTest() {
        try {
            request = this.getGetRequest("eHomeLogin.login.shtml5");
            sensitiveOp("", "queryCustomerList",request,  0);            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

15:22:26 Tests Passed: 1 passed

通过没有报错,进入单步调试代码

 public static void sensitiveOp(String empNo, String requestType, HttpServletRequest request, Integer operateResult, String operationType) {
        try {
            if(securityLogger.isTraceEnabled()) {
                String ignored = DateUtils.formatDate(new Date(), "yyyy-MM-dd hh:mm:ss");
                String url = request.getRequestURI();
                String ip = CommonUtil.getRemoteHost(request);
                Map parameterMap = request.getParameterMap();
                HashMap info = new HashMap();
                info.put("App_id", BasicSupportPropertiesUtil.getPropertyValues("sales.subsystem.name"));
                info.put("Company_code", "PA002");
                info.put("Request_url", url);
                info.put("Operation_result", "Success");
                info.put("Operation_user", empNo);
                info.put("Record_counts", operateResult);
                info.put("Server_ip", request.getLocalAddr());
                info.put("Operation_type", operationType);
                info.put("Request_type", requestType);
                info.put("Src_ip", ip);
                info.put("Operation_time", ignored);
                info.put("Operation_user_type", !StringUtils.isNumeric(empNo) && !StringUtils.startsWithIgnoreCase(empNo, "xn")?"2":"1");
                info.put("Operation_object", parameterMap.keySet());
                securityLogger.trace(GSON.toJson(info));
            }
        } catch (Excetion var10) {
            ;
        }

    }

多次调试,突然想到isNumeric方法是存在的,表达式遵循左匹配原则,!isNumeric为false,startsWithIgnoreCase方法不会执行,所以有成功的情况。

info.put("Operation_user_type", !StringUtils.isNumeric(empNo) && !StringUtils.startsWithIgnoreCase(empNo, "xn")?"2":"1");

更改方法第一个参数为“aaaa”,单测failed,重现成功。

然而当初为了避免方法内异常影响到功能,特意catch了exception,但还是影响了正常功能,应该用Throwable,重新打包,执行单测,测试案例通过了,方法内的error不会影响原功能了。

catch (Throwable var10) {
            ;
        }

总结

1、jar包功能单独测试的时候,案例执行覆盖全了,不代表被引用到别的系统也是正常的,会因为第三方jar包版本不一致报错。要谨慎对待每一次变更。
2、公共jar包方法为避免错误扩散,仅仅catch Exception 是不够的,应该用catch Throwable 。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值