异常处理
当Java虚拟机在执行应用程序的某个方法时遇到了非正常现象,jvm就会生成一个异常对象,把它抛给客户,以便向客户通报程序在运行中除了问题。客户可以是上层调用的方法或者终端用户。
Struts框架处理异常的机制建立在java处理异常的基础上。
1。java异常
1)java异常
java异常是在java程序运行时遇到的非正常情况而创建的对象,它封装了异常信息。java异常的根类为java.lang.Throwable.Throwable类有两个直接子类:java.lang.Error和java.lang.Exception。Error类表示程序本身无法恢复的严重错误。比如java虚拟机错误。Exception类表示可以被程序捕获并处理的错误。在Struts应用中自定义的异常必须直接或间接地继承Exception类。
Throwable:Error,Exception
Error:VirtualMachineError<-OutOfMemoryError
Exception:IOException<-RemoteException;RuntimeException<-ClassCastException
2)JVM的方法调用堆栈
JVM用方法调用栈来跟踪每个线程中的一系列的方法调用过程。该栈保存了每个调用方法的本地信息。对于独立java应用程序,可以一直回溯到该程序的入口方法main()。当一个新方法被调用时,JVM把描述该方法的栈结构置入栈顶,位于栈顶的方法为正在执行的方法。
如果方法中的代码块可能抛出异常,那么有两种处理方法:
a。try/catch语句捕获并处理异常。
b。在方法的声明处通过throws语句声明抛出异常。
当一个Java方法正常执行完毕,JVM会从调用栈中弹出该方法的栈结构,然后继续处理前一个方法。如果java方法在执行代码的过程中抛出异常,JVN必须找到能捕获该异常的catch代码块。它首先查看当前方法中是否存在这样的catch代码块,如果存在,就执行该catch代码块;否则,JVM会先从调用栈中弹出该方法的栈结构,继续到前一个方法中查找合适的catch代码块。最后,如果JVM向上追溯到main()方法,仍然没有找到处理该异常的代码块,该线程就会异常终止。如果该线程是主线程,应用程序也将随之终止,此事JVM将把异常直接抛给用户,在用户终端上会看到原始的异常信息。
在上述回溯过程中,如果JVM在某个方法中找到了处理该异常的代码块,则该方法的栈结构将成为栈顶元素,程序流程将转到该方法的异常处理代码部分继续执行。
3)异常处理对性能的影响
一般在Java程序中使用try/catch语句不会对应用的性能造成很大的影响。仅仅当异常发生时,JVM虚拟机需要执行额外的操作,来定位处理异常的代码块,这是会对性能产生负面影响。如果抛出异常的代码块和捕获异常的代码块位于同一方法中,这种影响就会小一些。如果JVM必须搜索方法调用堆栈来寻找异常处理代码块,其对性能的影响就比较大,尤其在异常处理代码块位于调用栈的最底部时,JVM定位异常处理代码块需要做大量的工作。
4)系统异常和应用异常
从开发应用的角度来看,异常可以分为系统异常和应用异常。
系统异常在性质上比应用异常严重。系统异常和应用逻辑无关,而是底层系统出现了问题。如数据库服务器异常终止,网络连接中断等。终端用户不能修复这种错误。
应用异常是由于违反了商业规则或者业务逻辑而导致的错误。可以把错误信息报告给用户,让用户进行相应的处理。
5)使用异常处理链
当不需要用户来处理和关心原始的异常时,常见的做法就是捕获原始异常,把它包装成一个新的不同类型的异常,再抛出新的异常。
JDK1.4版本中的Throwable类支持异常链机制。异常链机制就是把原始异常包装为新的异常类时,在新的异常类中封装了原始异常类。这有助于查找产生异常的根本原因。
6)处理多样化异常
在Java方法中一次只能抛出一个异常。要处理在一个方法中抛出多个异常的问题,需要自行设计支持多样化异常的异常类。
在自定义类中定义一个List变量放Exception
2。Struts框架异常处理机制概述
Struts框架在视图层和控制层提供了对异常处理的支持。Struts的控制器负责捕获各种异常。包括控制器运行中本身抛出的异常以及调用模型的业务方法时抛出的异常。当Struts的控制器捕获到异常后,在异常处理代码块中,创建描述异常信息的ActionMessage对象,把它保存在ActionMessages或其子类ActionErrors对象中,然后把ActionMessages保存在特定范围内。接下来视图层的<html:errors>标签检索特定范围内的ActionMessages对象,把本地化的错误消息输出到网页上。
3。Struts框架异常处理机制的细节
1)Java Web容器处理异常的机制
Struts框架提供了功能强大的通用错误处理机制,但是不能保证所有的错误或异常都能被捕获。当错误发生时,如果Struts框架不能处理这种错误,就把错误抛给Java web容器。Java Web容器先查看是否在web应用发布描述文件中配置了相应的<error-page>元素,如果存在该元素,就返回<error-page>元素的<location>子元素指定的错误页面;否则就把错误直接抛给用户。
2)ActionServlet类处理异常的机制
ActionServlet类的process()方法不捕获任何异常,仅仅声明向上层调用方法抛出IOException或ServletException。
3)RequestProcessor类处理异常的机制
RequestProcessor的process()方法不捕获任何异常,仅仅声明向上层调用方法抛出IOException或ServletException。
public void process (request,response)
throws IOException,ServletException{
...
ActionForward forward = processActionPerform(request,response,action,form,mapping);
...
}
RequestProcessor类在process()中调用自身的processActionPerform()方法,在processActionPerform()方法中调用Action类的execute()方法,执行具体的业务逻辑。
public ActionForward processActionPerform(request,response,action,form,mapping)
throws IOException,ServletException{
try{
return (action.execute(mapping,form,request,response));
}catch(Exception e){
return (processException(request,response,e,form,mapping));
}
}
在processActionPerform()方法中可以捕获Action类的execute()方法抛出的所有异常。在catch代码会肿调用自身的processException()方法来处理异常。
public ActionForward processException(request,response,exception,form,mapping)
throws IOException,ServletException{
//查看是否在struts配置文件中定义了异常处理器<exception>
ExceptionConfig config = mapping.findException(exception.getClass());
//如果没有配置异常处理器,就抛出IOException或ServletException
if(config == null){
if(exception instanceof IOException){
throw (IOException)exception;
}else if(exception instanceof ServletException){
throw (ServletException)exception;
}else{
throw new ServletException();
}
}
//如果配置类异常处理器,调用处理器的execute方法来处理异常。
try{
//创建异常处理类的实例
ExceptionHandler handler = (ExceptionHandler)RequestUtils.applicationInstance(config.getHandler());
return (handler.execute(exception,config,mapping,form,request,response));
}catch(Exception e){
throw new ServletException();
}
}
4)ExceptionHandler类处理异常的机制
Struts框架提供了默认的异常处理类org.apache.struts.action.ExceptionHandler,它的execute()方法负责处理异常。
public ActionForward execute(
Exception ex,
ExceptionConfig ae,
ActionMapping mapping,
request,
response)
throws ServletException{
ActionForward forward = null;
ActionMessage error = null;
String poroperty = null;
//先决定转发路径
if(ae.getPath() != null){
forward = new ActionForward(ae.getPath());
}else{
forward = mapping.getInputForward();
}
//把异常信息封装到ActionMessage中
if(ex instanceof ModuleException){
error = ((ModuleException)ex).getActionMessage();
property = ((ModuleException)ex).getProperty();
}else{
error = new ActionMessage(ae.getKey(),ex.getMessage());
property = error.getKey();
}
request.setAttribute(Globals.EXCEPTION_KEY,ex);
//把ActionMessage对象保存到ActionMessages对象中,再把ActionMessages对象存放在适当的范围内
this.storeException(request,property,error,forward,ae.getScope)());
return forward;
}
protected void storeException(request,property,error,forward,scope){
ActionMessages errors = new ActionMessages();
errors.add(property,error);
if("request".equals(scope)){
request.setAttribute(Globals.ERROR_KEY,errors);
}else{
request.getSession().setAttribute(Globals.ERROR_KEY,errors);
}
}
4。在Struts应用中处理异常的各种方式
1)创建异常类
在Struts的控制层,将把Java异常类包装为ActionMessage,视图从ActionMessage对象中读取错误信息。如果异常类包含的异常消息事先就和Struts的Resource Bundle绑定在一起,可以简化Struts控制层组件把Java异常类包装为ActionMessage的步骤。
在Struts应用中定义异常有两种方式:
a。扩展ModuleException类
b。创建自定义的异常类体系
扩展ModuleException类:
Struts中提供了专门的异常类,org.apache.struts.util.ModuleException,它是Exception类的子类。可以很好的和Struts Resource Bundle绑定。
ModuleException的构造方法:
ModuleException(String key)
ModuleException(String key,Object[] values)
key:错误消息key
values:设置复合消息中的参数的对象数组
ModuleException的缺点在于它是Struts控制层的组件,不能被模型层使用。如果在Action类的execute()方法中,如果捕获了来自模型层的异常,要先包装成ModuleException,才能继续把它抛出。
创建自定义的异常类体系
可以创建自己的异常类体系,模型层和控制层能够共用这些异常类。
2)由Java web容器捕获异常
Java Web容器捕获到异常时,先查看是否在web应用发布描述文件中配置了相应的<error-page>元素,如果存在该元素,就返回<error-page>元素的<location>子元素指定的错误页面;否则就把错误直接抛给用户。
3)以配置的方式处理异常
在Struts配置文件中,配置<exception>元素
<exception>元素的属性:
type:指定待处理的异常类
handler:指定异常处理类。默认值:org.apache.struts.action.ExceptionHandler。如果用户自定义的异常处理类,必须继承ExceptionHandler
path:转发路径
key:错误消息key
bundle:Resource Bundle。如果没有设置,使用默认的
scope:ActionMessages存放的范围。默认:request
4)以配置的方式处理异常
在Action类中以编程方式来处理异常。
a。在Action类中捕获异常
try{
...
}catch(Exception e){
...
}