问题描述
开发人员漏提交Java代码,测试人员在编辑器报错的情况下仍然进行打包操作,部署到was上运行时报错。
报错信息
webapp E com.ibm.ws.webcontainer.webapp.WebApp logError SRVE0293E: [Servlet Error]-[null]: com.ibm.ws.webcontainer.webapp.WebAppErrorReport:
at com.ibm.ws.webcontainer.webapp.WebAppDispatcherContext.sendError(WebAppDispatcherContext.java:624)
at com.ibm.ws.webcontainer.srt.SRTServletResponse.sendError(SRTServletResponse.java:1071)
at org.apache.struts2.dispatcher.Dispatcher.sendError(Dispatcher.java:770)
at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:505)
错误分析
问题根本原因
首先,在代码的最外层,已经添加了全部的异常捕获;发生这种捕获失败的情形,目前发现的可能原因:
- 编译class的Java源文件存在问题(这个是本文要讨论的问题)
- 存在class冲突,例如项目中引入不同版本的jar,中间件的class加载顺序决定是否会出现问题;可以参考:was设置共享库解决jar冲突
日志报错分析
was的报错关键信息是WebApp,说明它是应用端自身的一个error。不过奇怪的是,那一行既然报错了,但是为什么没有被外层的try-catch捕获呢?
这个说明try-catch捕获的力度不够,错误的等级比Exception还要高,也就是说要用Throwable错误(throwable和Exception的区别)
代码测试
// 常量类
Public class Constant{
Public class Payment{
public static final String HMCX = "00";
}
}
// 运行的类
public void test(){
System.out.printLn("开始");
try{
String code = Constant.Payment.HMCX;
System.out.printLn(code);
}catch(Exception e){
System.out.printLn("异常");
}
System.out.printLn("结束");
}
// 注释掉常量后,在编译器报错的情况下,仍然加载运行类反编译后的结果
public void test(){
throw new Error("Unresolved compilation problem: HMCX annot be resolved or is not a field");
}
// 增加Throwable 捕获
try{
test();
}catch(Exception e){
System.out.printLn("异常");
}catch(Throwable t){
// 如果在test方法存在编译错误的情况,会进入到该方法
System.out.printLn("无法运行的错误");
}
部署在Tomcat情形
将上面同样有问题的代码,部署在Tomcat服务器,只会报404,可是服务器没有任何日志输出。项目是ssh框架的(比较古老),通过debug模式,发现在如下struts框架的类的异常中进行了处理。
// org.apache.struts.xwork.xwork-core
// com.opensymphony.xwork2.DefaultActionInvocation.class
protected String invokeAction(){
...
try{
...
}catch(InvocationTargetException e){
Throwable t = e.getTargetException();
...
}
}
由于所有的请求都是访问xwork2.ActionSupport的实现类,也可以看出Struts2框架是通过反射进行调用实现ActionSupport的类。