收藏 分销(赏)

Struts技术研究-Exception.doc

上传人:仙人****88 文档编号:9452673 上传时间:2025-03-26 格式:DOC 页数:28 大小:232KB 下载积分:10 金币
下载 相关 举报
Struts技术研究-Exception.doc_第1页
第1页 / 共28页
Struts技术研究-Exception.doc_第2页
第2页 / 共28页


点击查看更多>>
资源描述
目录 第一章STRUTS EXCEPTION机制解析 3 1.1 异常处理概述 3 1.2 Java异常处理机制 3 1.2.1 Java Exceptions[1][3] 3 1.2.2 方法调用栈Java Stack[1][3] 4 1.2.3 Checked and Unchecked Exceptions[1] 4 1.2.4 Try/Catch结构对应用程序性能的影响[2] 4 1.2.5系统级异常和应用程序级异常 5 1.2.6 使用异常链Chained Exceptions 5 1.3 Struts异常处理机制 6 1.3.1 声明性异常处理declarative exception handling[1][2][3][4] 6 1.3.1.1在配置文件struts-config.xml中配置声明性异常处理 6 1.3.1.2 声明性异常处理器org.apache.struts.action.ExceptionHandler 8 1.3.2 程序性异常处理Programmatic Exception Handling[1] 9 1.3.3 Struts异常处理流程 14 第二章STRUTS LOGGING机制解析 16 2.1 使用服务器日志文件记录日志 16 2.2 使用过滤器记录日志 16 2.2.1创建过滤器类 16 2.2.2在网络应用程序配置文件web.xml中配置过滤器 17 2.2.3 在服务器中放置过滤器及其资源 17 2.3 在struts框架中使用Log4j 17 2.3.1 Log4j基本结构[1][5] 18 2.3.2 Logger 18 2.3.3 Appender 18 2.3.4 Layout 19 2.3.5 Appender+Layout三种常用组合方式 19 2.3.6 Log4j的配置文件 22 结束语 24 参考文献 25 致 谢 26 翻译 英文稿 27 Hibernate in Action: Practical Object/Relational Mapping 27 翻译 中文稿 40 Hibernate in Action: Practical Object/Relational Mapping 40 第一章Struts Exception机制解析 1.1 异常处理概述 当处理过程中出现问题是,Java用抛出异常的方法来通知客户端。抛出的异常中包含了所发生问题的类型以及告诉客户端是什么原因导致了异常的发生,如果客户端不处理异常,JVM(Java虚拟机)采取默认的处理方式。在Struts中处理异常与在通常情况下处理异常差别不是很大,主要区别在于抛出异常的方式和异常所表示的struts的特殊信息。 1.2 Java异常处理机制 因为Struts异常是基于Java异常处理机制的,因此首先介绍标准Java异常处理。 1.2.1 Java Exceptions[1][3] 在Java中,异常是一个对象,当应用程序处理过程中符合异常条件时,就创建一个基于java.lang.Throwable类的实例,Throwable有两个子类java.lang.Error 和java.lang.Exception在Java核心类库中,Throwable类的子类超过100个,下面框架图仅显示了几个常用的子类: 一般情况下,Exception分支及其所有的子类如输入输出异常IOException、运行时异常RunTimeException、远程异常RemoteException、类异常ClassCastException等都能被应用程序处理,Struts框架中产生和抛出的所有异常必须继承Exception类。Throwable的另一个分支Error分支及其所有子类被用于更严重的错误。如内存不够或内存溢出等错误,显然客户端没有能力处理此类错误,因此客户端通常不处理此类错误,由JVM自己处理。 1.2.2 方法调用栈Java Stack[1][3] JVM通过方法调用栈的形式来保存线程执行时调用的方法序列,栈中保存了每个被调用方法的本地信息以及返回应用程序Main()函数的路径。系统只执行栈顶的方法,当调用新的方法时,包含方法信息的栈结构stack frame被压入栈顶,然后系统开始执行栈顶的新方法。当方法正常的执行完时,系统弹出栈顶的栈结构,执行以前压入的方法,然而当异常发生时,JVM必须找到相应的异常处理器。JVM首先检查当前方法是否捕获了异常或其父类异常,若是,继续执行catch程序段,如果当前的catch程序段未提供处理异常的方法,JVM从栈中弹出方法的栈结构,直到找到该异常或其父类异常的处理器为止,如果弹出栈结构直到底层的main()方法还没有找到异常的处理器则终止线程。如果该线程是主线程并且没有其它的非后台线程non-daemon在执行,则终止应用程序。如果JVM找到了该方法异常处理器,则将该方法的栈结构置于栈的顶层,系统继续执行该方法。 栈结构示意图: An example of a Java method invocation stack Current frame and top of the stack Current method Address.getFullAddress() Stack Frame for method getFullAddress() Java Stack Stack Frame for method getCustomerAddress() Customer.getAddress() Stack Frame for method Main() Example.main() 1.2.3 Checked and Unchecked Exceptions[1] Java的所有异常都能被归为两类checked需要检查的和unchecked不需要检查的,这主要是针对编译器和JVM来说的。所有checked异常必须被处理,在方法中捕获checked异常并定义处理方法以及在throws程序段定义相应的异常信息。在程序编译阶段,编译器和JVM会检查所有checked异常是否在方法中被定义了处理逻辑,若没有则会产生编译错误。编译器和JVM会忽略对unchecked型异常的检查,通常这些异常是用户本身无法处理的。 1.2.4 Try/Catch结构对应用程序性能的影响[2] 当异常发生时JVM会查找适当的异常处理器来处理异常,如果在发生异常的方法中catch程序段包含了异常处理器,JVM直接调用本方法即方法栈中栈顶元素中的异常处理器即可,这时对系统的性能影响很小,但是如果发生异常的方法中catch程序段没有异常处理器,则JVM必须在方法栈中弹出顶层栈结构,在下一层栈结构中查找处理器,直至找到为止,这时就严重影响了系统性能。这就是为什么try/catch结构只允许用于异常处理而不是控制程序流程的根本原因,同时尽量把异常处理器包含在本方法中的catch程序段中。如下面的程序段:检查数值是否正确,不正确则设置默认值 Double basePrice = null; String basePriceStr = request.getParameter( "BASE_PRICE_AMOUNT" ); try{   basePrice = Double.valueOf( basePriceStr ); }catch( NumberFormatException ex ){    basePrice = ApplicationDefaults.DEFAULT_BASE_PRICE; } try中是出错条件,catch中是出错处理,catch包含在本层方法中 1.2.5系统级异常和应用程序级异常 异常从高层看可以分为系统级和应用程序级,系统级异常通常是与应用程序逻辑和客户端无关的,无法恢复的底层错误。系统级异常大多数是unchecked型异常,不在catch程序段中包含对它们的处理逻辑,因为它们是如此的严重以至于应用程序根本就无法处理。因此对系统级异常的处理不是试图补救和恢复,通常是向客户端返回系统错误页面,同时将栈中系统错误的详细信息写入日志,以便给系统管理员作参考。 应用程序级异常通常是由于违反了业务逻辑或者应用程序本身逻辑产生的异常。如在银行账户系统中,用户试图登陆已被锁定的账户时会产生应用程序级异常,因为用户违反了业务逻辑。对应用程序级异常的处理通常尽量给客户端补救的机会,在异常处理中把控制返回给客户端并给出友好的出错信息。如在本例中,应用程序应该向客户端重新返回输入界面并且提醒用户账户已经被锁定。 1.2.6 使用异常链Chained Exceptions 在实际应用中往往会这样处理异常:捕获一种异常但抛出的是另外一种。这是因为在有些情况下客户端不需要知道或者对原始的异常信息不感兴趣。例如客户端要上传图片文件至数据库,涉及异常的代码如下: public void updateImageFile( String imagePath ) throws UploadException; 如果在上传过程中发现问题则抛出上传异常UploadException,然而UploadException只是高层异常,具体的错误信息要复杂的多,可能是数据库满了或者数据库中已经有了该文件,或者网络中断了,因此原始异常是IOException 输入输出异常或者SQLException数据库异常,但是用户不需要知道如此详细的信息,用户只要知道文件上传失败了。所谓捕获一种异常但抛出的是另外一种是指捕获原始异常但是向用户抛出用户感兴趣的高层异常。使用异常链方法还有一个好处是增加了系统的灵活性,因为底层异常往往跟具体问题相关,并且引起异常的情况很多,这使得底层异常绑定在了具体应用上,而使用高层异常在一定程度上可以避免这些问题。 Java没有提供封装原始异常的方法,因此必须自己定义,由于其重要性,下面给出实现的核心代码: import java.io.PrintStream; import java.io.PrintWriter; public class BaseException extends Exception {   protected Throwable rootCause = null;   protected BaseException( Throwable rootCause ) {     this.rootCause = rootCause;   }   public void setRootCause(Throwable anException) {     rootCause = anException;   }   public Throwable getRootCause(  ) {     return rootCause;   }   public void printStackTrace(  ) {     printStackTrace(System.err);   }   public void printStackTrace(PrintStream outStream) {     printStackTrace(new PrintWriter(outStream));   }   public void printStackTrace(PrintWriter writer) {     super.printStackTrace(writer);     if ( getRootCause(  ) != null ) {       getRootCause(  ).printStackTrace(writer);     }     writer.flush(  );   } } 上面的程序段允许开发者通过Exception类的实例或者其继承者封装Throwable,这个特性使得开发者可以抽象底层的异常信息。该程序段同时也提供了获得底层异常的方法,以便将底层异常信息写入日志,有助于开发者分析具体问题。 1.3 Struts异常处理机制 struts中的异常处理包含声明性异常处理和程序性异常处理两种方式。 1.3.1 声明性异常处理declarative exception handling[1][2][3][4] 1.3.1.1在配置文件struts-config.xml中配置声明性异常处理 声明性异常处理方式是在外部XML文件中详细的描述异常处理策略,包括抛出何种异常及其如何处理。这种处理方式使得开发者很容易更改异常处理逻辑,并且更改后不需要重编译应用程序。Struts中声明性异常在配置文件struts-config.xml中配置的。下面详细介绍struts配置文件中有关异常处理的元素。 A Struts configuration file that uses declarative exception handling <struts-config> < global-exceptions > <exception key=" security.error.loginfailed" type="com.oreilly.struts.framework.exceptions.InvalidLoginException" path="/login.jsp"/> < /global-exceptions > <action-mappings> <action path="/login" type="com.oreilly.struts.storefront.security.LoginAction" name="loginForm" scope="request" input="/login.jsp"> <exception key="security.error.changepassword" path="/changePassword.jsp" type="com.oreilly.struts.framework.exceptions.ExpiredPasswordException"/> <exception key="security.error.accountlocked" type="com.oreilly.struts.framework.exceptions.AccountLockedException" path="/accountLocked.jsp"/> </action> </action-mappings> </struts-config> 下面介绍配置文件中的各个元素: < global-exceptions />:定义全局性的异常信息,在这里定义的异常信息能够被<action-mappings/>元素中的任意<action/>元素调用。 <exception/>:定义异常处理器,包含下列属性 bundle:定义资源绑定文件,即异常处理时所需要的资源信息,用于异常信息的国 际化,默认情况下是调用此异常处理器的Action的Action.MESSAGES_KEY handler:指定异常处理器,即包含配置文件中异常处理逻辑的java类位置,默认为org.apache.struts.action.ExceptionHandler key:用于出错信息国际化的资源绑定键 path:若发生异常,则将处理转移至path指定资源 scope:指定错误结果集访问范围,是”request”还是”session”,默认为session范围 type:所以处理的异常的java类 上面的例子包含一个全局异常和两个<action />内的局部异常,全局异常表示如果发生登陆无效异常InvalidLoginException,则控制器将控制转移至登陆页面login.jsp处理,其它两个异常的处理情况类似。 Struts在处理异常时如果发生的异常不是程序性异常,则控制器核心请求处理器RequestProcessor会遍历配置文件struts-config.xml,根据<exception/>元素中的type属性查找与所发生异常相应的<exception/>元素。 1.3.1.2 声明性异常处理器org.apache.struts.action.ExceptionHandler struts提供的默认处理器ExceptionHandler负责从配置文件中提取yichang信息,处理声明性异常,下面摘录了该处理器的核心代码,通过分析该代码得出处理流程 //下面的处理器对核心处理器源码做了一些扩展,主要扩展了资源绑定能力,但是不影响总体流程的分析 public class SpecialExceptionHandler extends ExceptionHandler { //异常处理器中的execute()方法负责了处理流程 protected ActionForward execute(Exception ex, ExceptionConfig config, ActionMapping mapping, ActionForm formInstance, HttpServletRequest request, HttpServletResponse response) throws ServletException { //定义ActionForward对象,用于将控制转移至指定资源处理 ActionForward forward = null; //定义ActionError,记录出错信息 ActionError error = null; String property = null; //获得转移资源位置,系统可以在两处地方得到控制所要转移到的资源位置,一种是通过<exception/>元素中的path属性,另一种是通过<action />元素中的input属性,因此首先在<exception/>元素中查找path值,若未定义,再在<action />元素中查找input值 String path = null; if (config.getPath( ) != null) { path = config.getPath( ); }else{ path = mapping.getInput( );} //将获得的指定资源位置作为参数配置控制转移的forward对象 forward = new ActionForward(path); //根据<exception/>元素中的资源信息键key获得预定义的该异常的出错信息 if( ex instanceof BaseException) { BaseException baseException = (BaseException)ex; String messageKey = baseException.getMessageKey( ); Object[] exArgs = baseException.getMessageArgs( ); //检查该资源信息是否包含参数,若有则获得参数 if ( exArgs != null && exArgs.length > 0 ){ error = new ActionError( messageKey, exArgs ); }else{ //创建带有参数的资源信息的错误对象error error = new ActionError( messageKey ); } }else{//创建没有参数的资源信息的错误对象error error = new ActionError(config.getKey( )); property = error.getKey( ); } //通过查找<exception/>元素的scope或<action/>元素的scope获得作用范围,将错误结果存入相应的作用范围 storeException(request, property, error, forward, config.getScope( )); //返回带有转移资源信息的forward对象 return forward; } } 流程示意图: struts-config.xml <exception key=" error.changepassword" path="/changePassword.jsp" scope=”request” ExceptionHandler 找到控制要转移到的资源位置 配置ActionForward对象 获得资源信息 以获得的资源信息为参数创建Error对象 struts-config.xml <action include=”/changePassword.jsp” scope=”request” 查找异常作用范围 将Error对象存入相应的作用范围 返回ActionForward对象 changePassword.jsp <error/> 资源绑定文件: error.changepassword: 输入的密码不匹配 作用范围(request): 存储Error信息 在JSP页面输出异常信息: ERROR: 输入的密码不匹配 1.3.2 程序性异常处理Programmatic Exception Handling[1] 程序性异常处理方式是传统的异常处理,将异常产生和处理逻辑放入具体的方法中,也就是在具体的方法中硬编码,而不象声明性异常处理方式那样只要改动配置文件就行了。在1.2.5节中介绍了系统级异常和应用程序级异常。对于应用程序级异常,程序性异常处理流程大致是这样的:首先将异常信息记录在日志中,然后创建ActionError错误对象,将其存储在相应的范围中,最后通过ActionForward将控制转移至相应的资源去处理。整个过程和声明性异常的处理过程差不多,只是声明性异常处理方式不需要将异常信息记录在日志中。对于系统级异常,所作的工作仅仅是将异常信息记录在日志中,然后直接返回系统错误信息。 程序性异常处理方式必须在调用异常的方法中嵌入try/catch程序块,里面包含了产生异常的条件和异常处理器。在struts中采用程序性异常处理方式比较复杂,下面通过分析源程序核心代码来归纳处理流程。 首先分析在方法中必须实现的try/catch程序块包含哪些内容,下面是经典的模板程序: The execute( ) method of the BaseAction public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { ActionForward forwardPage = null; ---------------------------------------------------------------------------------------------------------------- //产生异常 try{ UserContainer userContainer = getUserContainer( request ); //调用executeAction( ) 方法产生异常,executeAction( ) 方法调用Action及其子类的try/catch程序块 forwardPage = executeAction(mapping, form, request, response, userContainer); } ---------------------------------------------------------------------------------------------------------------- //处理应用程序级异常 catch (BaseException ex){ // 使用自己的日志框架将应用程序级异常记录在日志中 Logging…… // 调用通用的异常处理器处理异常,这里由processExceptions()方法负责 forwardPage = processExceptions( request, mapping, ex ); } ---------------------------------------------------------------------------------------------------------------- //处理系统级异常 catch (Throwable ex){ //使用自己的日志框架将系统级异常记录在日志中 // 将异常信息返回给系统出错信息页 request.setAttribute( Action.EXCEPTION_KEY, ex ); // 处理其它的系统级异常 forwardPage = mapping.findForward( IConstants.SYSTEM_FAILURE_KEY ); } return forwardPage; } 因为系统开发者所能控制的是程序级异常,在execute()方法中调用了processExceptions()方法处理程序级异常,下面重点讨论processExceptions()方法 The processExceptions( ) method in the BaseAction protected ActionForward processExceptions( HttpServletRequest request, ActionMapping mapping, BaseException ex ){ //定义错误结果集ActionErrors的对象和负责转移控制的ActionForward的对象 ActionErrors errors = new ActionErrors( ); ActionForward forward = null; --------------------------------------------------------------------------------------------------------------------- // 得到用户的本地化信息,若没有配置,则采用系统默认设置 Locale locale = getUserContainer( request ).getLocale( ); if (locale == null){ locale = Locale.getDefault( ); } --------------------------------------------------------------------------------------------------------------------- // 调用processBaseException()方法处理方法调用栈顶层的栈结构也就是处理当前的异常 processBaseException(errors, (FieldException) ex, locale); --------------------------------------------------------------------------------------------------------------------- //查找配置文件中<action/>元素的input属性或者定义了失败转移的forward属性,因为系统在这两处地方定义了该Action类发生异常后将控制转移至input属性或forward属性指定的资源处理,先查找input属性,若未定义,再查找forward属性 String inputStr = mapping.getInput( ); String failureForward = mapping.findForward(IConstants.FAILURE_KEY); if ( inputStr != null) { forward = new ActionForward( inputStr ); }else if (failureForward != null){ forward = failureForward; } --------------------------------------------------------------------------------------------------------------------- //检查方法调用栈中是否还有其它的异常,若有,则循环处理 List exceptions = ex.getExceptions( ); if (exceptions != null && !exceptions.isEmpty( ) ){ int size = exceptions.size( ); Iterator iter = exceptions.iterator( ); while( iter.hasNext( ) ){ // All subexceptions must be BaseExceptions BaseException subException = (BaseException)iter.next( ); processBaseException(errors, subException, locale); } } --------------------------------------------------------------------------------------------------------------------- //保留所有的错误结果集Errors saveErrors( request, errors ); --------------------------------------------------------------------------------------------------------------------- //处理结束返回ActionForward的对象 return forward; } processExceptions()方法调用processBaseException()方法创建了包含异常错误信息并且经过国际化的ActionErrors对象,因为异常处理的核心问题是向客户端返回有关该异常的错误信息,因此下面再详细论述创建错误结果集的processBaseException()方法 The processBaseException( ) method of the BaseAction class protected void processBaseException( ActionErrors errors, BaseException ex, Locale locale) { // 创建ActionError对象 ActionError newActionError = null; // 得到资源绑定键 String errorCode = ex.getMessageKey( ); //察看资源绑定信息是否包含参数,若有,则获得参数列表 Object[] args = ex.getMessageArgs( ); // 根据获得的资源绑定信息创建ActionError对象,分为带有参数和不带参数两种 if ( args != null && args.length > 0 ){ // Use the arguments that were provided in the exception newActionError = new ActionError( errorCode, args ); }else{ newActionError = new ActionError( errorCode ); } //将ActionError对象加入全局性的错误结果集ActionErrors.GLOBAL_ERROR errors.add( ActionErrors.GLOBAL_ERROR, newActionError ); } 以上是程序性异常处理方式的基本流程,很明显,整个处理流程要比声明性异常处理方式复杂的多,和声明性
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 教育专区 > 小学其他

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2025 宁波自信网络信息技术有限公司  版权所有

客服电话:4009-655-100  投诉/维权电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服