下面会给出详细代码, 这个空指针不是那么好一眼看出来, 不过最后, 该 bug 就是在没有重启服务, 也没在本地调试的情况下解决的, 利用的方法就是 JSP. 没错, 就是这么古老的技术. 现在很多 90 程序员已经慢慢成为主力了, 对于 JSP 这类技术估计都不了解, 尤其现在前后端分离后, 互联网领域的公司, 包括一些传统行业的新的项目, 后端服务都只是简单的 API 服务. 下面演示下, 怎么利用 JSP 来找 BUG, 一点不难, 主要是提供一个思路吧.(不适用于打成 jar 包的 spring boot 应用, 对于 打成 war 包的 spring boot 项目是否支持, 我还没实验, 有兴趣同学可以试试)
二, 问题描述
1, 问题代码
如图所示, npe 抛出的那行, 暂时也确定不了到底是哪个空了. jsonObj 来自于 array,array 来自 resultList,resultList 来自 incidentInformationDao.queryAllIncidentInformation, 然后又被 gisCommonService.getCoordinatesWithinCircle 处理了.
大概又看了一眼 gisCommonService.getCoordinatesWithinCircle 的代码:
看着这一坨坨的代码, 而且不是我写的, 而且没什么注释, 而且 bug 还要我来看... 哎...
我就想了, 我要看看到底 在执行了 gisCommonService.getCoordinatesWithinCircle 后, 要是可以直接把 List<GisAccessAlarm> resultList 打印出来, 不是一下就清晰了吗?
说干就干, 本来 @Java web 程序员, 我们一起给程序开个后门吧: 让你在保留现场, 服务不重启的情况下, 执行我们的调试代码 这个博文里提供了一种方式, 但是这个测试环境的工程还没搞上这个东东, 无奈, 用不了.
但是, emmm, 等等, JSP 不是可以吗?
2,jsp 文件代码
- test.jsp:
- <%@ page import="com.alibaba.fastjson.JSONArray" %>
- <%@ page import="com.*.base.common.exception.IllegalParameterException" %>
- <%@ page import="com.*.base.common.utilities.JsonUtils" %>
- <%@ page import="com.*.base.common.utilities.SpringContextUtils" %>
- <%@ page import="com.*.dao.interfaces.IncidentInformationDao" %>
- <%@ page import="com.*.model.IncidentAppealInformation" %>
- <%@ page import="com.*.model.IncidentInformation" %>
- <%@ page import="com.*.service.impls.GisIncidentInformationServiceImpl" %>
- <%@ page import="com.*.service.interfaces.IGisService" %>
- <%@ page import="com.*.service.interfaces.IncidentAppealService" %>
- <%@ page import="com.*.service.interfaces.IncidentInformationService" %>
- <%@ page import="com.*.utils.GisUtils" %>
- <%@ page import="com.*.vo.GisAccessAlarm" %>
- <%@ page import="org.apache.commons.collections.CollectionUtils" %>
- <%@ page import="org.apache.commons.lang3.StringUtils" %>
- <%@ page import="org.slf4j.Logger" %>
- <%@ page import="org.slf4j.LoggerFactory" %>
- <%@ page import="java.util.Calendar" %>
- <%@ page import="java.util.Date" %>
- <%@ page import="java.util.List" %>
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <%@page contentType="text/html;charset=UTF-8" %>
- <HTML xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta charset="UTF-8">
- <meta http-equiv="pragma" content="no-cache">
- <meta http-equiv="cache-control" content="no-cache">
- <meta http-equiv="expires" content="0">
- <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
- <meta http-equiv="description" content="This is my page">
- </head>
- <% Logger logger=L oggerFactory.getLogger(GisIncidentInformationServiceImpl.class);
- IncidentInformationService incidentInformationService=S pringContextUtils.getBean(IncidentInformationService.class);
- IncidentAppealService incidentAppealService=S pringContextUtils.getBean(IncidentAppealService.class);
- IncidentInformationDao incidentInformationDao=S pringContextUtils.getBean(IncidentInformationDao.class);
- IGisService gisCommonService=S pringContextUtils.getBean(IGisService.class);
- String incidentInformationId="B06BBE52-E85F-450C-A8C6-EB45D2634EED" ; Integer
- radius=2 000; Integer startTime=1 0; Integer endTime=1 0; if (StringUtils.isEmpty(incidentInformationId))
- { throw new IllegalParameterException(
- "IncidentinformationID is null or empty."); } IncidentInformation incidentInfo=i ncidentInformationService.get(incidentInformationId);
- IncidentAppealInformation incidentAppealInformation=i ncidentAppealService.get(incidentInformationId);
- if (incidentInfo==n ull || null==i ncidentAppealInformation) { throw new
- IllegalParameterException(
- "incidentinformationID is not found in db. IncidentinformationID =" + incidentInformationId); } String type=i ncidentInfo.getIncidentTypeId();
- type=S tringUtils.substring(type, 0, 2); if (StringUtils.isEmpty(type))
- { throw new IllegalParameterException(
- "incidentinformation type is empty."); } String lonStr=i ncidentInfo.getLongitude(); String latStr=i ncidentInfo.getLatitude();
- GisUtils.checkLonLat(lonStr,latStr); Date appealTime=i ncidentAppealInformation.getIncidentTime();
- Calendar cal=C alendar.getInstance(); cal.setTime(appealTime); cal.add(Calendar.MINUTE,
- -1 * startTime); Date startDate=c al.getTime(); Calendar cal1=C alendar.getInstance();
- cal1.setTime(appealTime); cal1.add(Calendar.MINUTE, 1 * endTime); cal1.add(Calendar.SECOND,
- 1); Date endDate=c al1.getTime(); List<GisAccessAlarm>
- resultList = incidentInformationDao.queryAllIncidentInformation(incidentInformationId,
- type, startDate, endDate); if (null != resultList && CollectionUtils.isNotEmpty(resultList))
- { resultList = gisCommonService.getCoordinatesWithinCircle(resultList,
- Double.valueOf(lonStr), Double.valueOf(latStr), radius.doubleValue());
- } JSONArray array = JsonUtils.toFormatDateJSONArray(resultList); logger.info("array:{}",array);
- %>
- <body>
- </body>
- </HTML>
你大概看到了, 我写了这么大一坨, 我这么懒, 肯定是不可能手写, 拷过来, 然后把本来自动注入的那些, 改成从 SpringContextUtils 静态工具中获取就行了. 我们这里, 重点代码就一行, 也就是标红的 82 行.
3, 执行 jsp
然后我就把这个 jsp 丢到了 Web 应用的根目录下:
然后从我的浏览器访问之:
http://192.168.19.97:8080/web 应用上下文 / test.jsp
执行后, 去看看我们的日志文件:
把 array 序列化之后, 一看, 原来是没有 userId 这个属性存在...
于是, 下面这行红色处, 肯定就空了:
jsonObj.put("userName", userService.getUserMap().getOrDefault(jsonObj.get("userId"),jsonObj.get("userId").toString()));
三, 总结
JSP 这种方式, 说起来还是挺方便的, 可以马上修改, 马上看到效果. 但是背后的原理我们也需要了解, 再看看 Tomcat 的类加载器图 (来自于网络, 侵删):
可以看到, JSP 的类加载器处于最下面一层, 每次访问 JSP 时, 如果 JSP 文件已经被修改过 (通过文件的最近一次修改时间确定), 都会生成一个新的 JSP 类加载器. JSP 类加载器 加载的对象, 为什么能够和 WebApp 类加载器加载的类交互呢 (比如我们上面例子中, JSP 文件中引用了很多 java 代码, 甚至用了里面的 spring 的 bean), 这都是因为 JSP 类加载器的双亲加载器 就是 WebApp 类加载器, JSP 类加载器在遇到自己加载不了的那些类时, 都委派给 WebApp 类加载器去加载了, 所以 Jsp 文件中引用的那些类, 最终是由 Webapp 类加载器加载的, 所以才可以调用那些 java 代码. 如果我们自己自定义个类加载器, 这个类加载器除了加载 jsp 文件, 也自己去 Web-inf 下面加载想要的类, 那么, 肯定是会出错的, 具体表现就是:
IncidentInformationService incidentInformationService = SpringContextUtils.getBean(IncidentInformationService.class);
这一句中, SpringContextUtils 如果由自己加载, 那么 SpringContextUtils 里面是没有任何 bean 存在的, 取出来的都为 null, 也就不能达到我们动态调试的效果了.
来源: https://www.cnblogs.com/grey-wolf/p/11052495.html