`

难经4:Struts2,拦截器拦不住的异常?!

阅读更多

[问题]

在解难经3:Struts2,拦截器拦不住Result?中,碰到的一个难题,当在PreResultListener中的抛出异常时,总是不能跳转到配好的异常页面去,而是抛出ServletException。换句话说,异常映射拦截器(具体来说指由XWork提供的ExceptionMappingInterceptor),根本拦截不住这种异常。按理说,不应该这样啊,Action里的异常是可以被捕捉并跳转到相应的错误处理页面的,到底是哪里出的问题?

 

由于春节回湖南老家过年了,这个问题也暂时搁置下来。

[探幽]

过年在家的时候,脑袋里经常回想到这个问题,初步的分析结果是,问题应该出在Struts2和XWork的核心类,以及异常映射拦截器的异常处理这几个地方。 

演员表

 在分析这个问题之前,有必要介绍一下一些基本情况,下面就对分析过程中,几个即将登场的核心类演员一一介绍(按出场顺序排序),他们在Struts2的每次请求处理中,都扮演重要角色:

0、姓名:过滤分发器(FilterDispacher)

     单位:Struts2

     职责:初始化分发器,根据请求查找对应的Action映射配置,并调用分发器处理请求,执行Action

1、姓名:分发器(Dispacher)

     单位:Struts2

     部门:org.struts2.dispacher

     职责:接受从过滤器分发过来的请求,并执行对应的Action

2、姓名:动作代理(ActionProxy、StrutsActionProxy)

     单位:XWork(ActionProxy)、Struts2(StrutsActionProxy)

     职责:负责维持Action配置,调用动作调用器

3、姓名:动作调用器(ActionInvocation、DefaultActionInvocation)

     单位:XWork

     职责:负责维持Action调用过程中的状态,调用拦截器和最终的Action方法

4、姓名:拦截器(Interceptor、ExceptionMappingInterceptor)

     单位:XWork

     职责:负责在调用Action方法进行拦截,实现可扩展的功能处理,如异常映射拦截器实现异常时自动跳转到错误页面的功能

5、姓名:动作(Action)

     单位:XWork

     职责:负责最终的请求业务处理实现

6、姓名:结果(Result)

     单位:XWork

     职责:负责最终的响应页面的生成

 

除了上述核心类做主角,在本次解难剧本中,下面的几个跑龙套的家伙也必不可少:

 

7、姓名:结果前置监听器(PreResultListener、测试用匿名实现类)

     单位:XWork(接口)、liuu(匿名测试监听处理类实现

     职责:在Action执行之后,Result执行之前触发该事件监听器,方便应用做出特定的处理;在匿名实现类中,模拟抛出异常

8、姓名:测试拦截器(HelloInterceptor)

     单位:liuu

     职责:自定义拦截器实现,模拟在特定位置抛出异常

9、姓名:测试动作(HelloAction)

     单位:liuu

     职责:自定义Action实现,模拟某个业务请求处理

 

 另外,请求(resquest)是贯穿全剧的道具。

 

接下来,我们布置一下场景:

1、使用Struts2提供的空白项目war包(我用的是struts2-blank-2.0.11.war),导入到Eclipse中作为测试项目

2、创建HelloInterceptor并配置为hello拦截器,可以根据请求参数(如P1)在拦截器中抛出一个异常(E1),

3、在HelloInterceptor中,为ActionInvocation增加一个匿名测试结果前置监听器类,根据请求参数(P2)抛出异常(E2)

4、开发一个空的HelloAction类,配置默认拦截器栈和hello拦截器

6、开发一个正常业务页面hello.jsp,并配置为HelloAction的success结果页面

5、开发一个错误显示页面error.jsp,并配置为全局异常结果页面error

 

 

好了,演员悉数登场,场景布置完毕,好戏开锣。 

场景一:正常处理请求

场景描述

1、在Tomcat下启动项目,打开URL:http://localhost:8080/struts2-blank-2.0.11/example/hello.action

2、正常显示hello.jsp页面

 

执行分析:在请求得到正常处理时,各大旦角各司其责,配合默契,整体非常流畅:

 



 

 从这个时序图里,我们可以看出,真正的主角,是动作调用器(DefaultActionInvocation),中心方法是invoke:

 1、依次遍历调用Action的拦截器栈

 2、在栈底,执行Action

 3、如果没有执行过(executed,默认为false),则执行:

      3.1 查询是否有结果前置监听器,如果有则顺序调用

      3.2 如果需要执行过结果Result(默认为true),则执行之

      3.3 设置为已执行状态(executed=true)(注意这一点,这是理解本次难经的关键

 

场景二、动作执行异常

场景描述

1、在Tomcat下启动项目,打开URL:http://localhost:8080/struts2-blank-2.0.11/example/hello.action?action

2、action参数触发HelloAction抛出异常,最终跳转到error.jsp页面

 

场景分析

如果对场景一理解清楚了,那么,对动作(Action)执行异常时,所发生的一切,应该不难了解:

1、HelloAction抛出异常时,由于里层的拦截器没有catch,因此拦截器层层退栈

2、退到ExceptionMappingInterceptor后异常被catch在查询全局异常映射配置后,返回调用结果为error

3、后续处理同场景一

 


场景三:监听器调用异常

场景描述

1、在Tomcat下启动项目,打开URL:http://localhost:8080/struts2-blank-2.0.11/example/hello.action?inner

 

2、inner参数将触发HelloInterceptor中的匿名PreResultListener抛出异常

3、但是最终却显示500错误,ServletException异常,而不是跳转到error.jsp页面



 

 

场景分析

现在,问题来了。既然在Action中抛出异常时,可以自动跳转到错误页面,为什么结果前置监听器里抛出的异常时,不能跳转到error.jsp,而是抛出ServletException呢?

 

来看看奥妙在哪里吧:

 


发现问题在哪了么:

关键的问题是,在PreResultListener抛出异常后,PreResultListener又被多执行了一次!
 

我们来看看关键代码,截取自DefaultActionInvocation.invoke:

    		if (!executed) {
    			if (preResultListeners != null) {
    				for (Iterator iterator = preResultListeners.iterator();
    					iterator.hasNext();) {
    					PreResultListener listener = (PreResultListener) iterator.next();
    					
    					String _profileKey="preResultListener: ";
    					try {
    						UtilTimerStack.push(_profileKey);
    						listener.beforeResult(this, resultCode);
    					}
    					finally {
    						UtilTimerStack.pop(_profileKey);
    					}
    				}
    			}

    			// now execute the result, if we're supposed to
    			if (proxy.getExecuteResult()) {
    				executeResult();
    			}

    			executed = true;
    		}

 原来:

1、在第一次调用PreResultListener时,第一个异常抛出,当前线程退栈;执行不到“executed = true ",execute是false

2、在ExceptionMappingInterceptor捕捉到这个异常后,返回结果码error

3、线程继续退栈,直到退出所有拦截器,然后会重新执行上述代码

4、由于execute还是false,所有PreResultListener被再次执行,于是又抛出第二个异常

5、对于这个新的异常,ExceptionMappingInterceptor已经无能为力,直到Dispachter再次捕捉到这个异常,并转为ServletException抛出

6、Servlet容器catch了这个异常,转到默认异常页面,上面显示的就是Tomcat的默认异常页面

。。。。。。

 

唉,问题已经完全清楚了,或许,这应该算Struts2(这里是2.0.11)的一个bug,不知道最新版里是否有修正。

 

[解难]

搞清楚了原因,解决起来那就是手到擒来了:只要让PreResultListener不能再次执行,一切就OK了。

 

我给匿名PreResultListener实现类增加一个状态字段executed,防止其多次执行:

		final ActionProxy ap = ai.getProxy();
		ai.addPreResultListener(new PreResultListener() {
			private boolean executed = false;

			public void beforeResult(ActionInvocation invocation,
					String resultCode) {
				if (!executed) {
					if (req.getParameter("fixed") != null)
						executed = true;
					
					System.out.println("in pre result listener ");
					if (req.getParameter("inner") != null) {

						throw new RuntimeException(
								"exception in intercept befor result in inner class : "
										+ req.getParameter("inner"));

					}
				}
			}
		});

场景四:解难

 

场景描述

再次部署后,打开URL:http://localhost:8080/struts2-blank-2.0.11/example/hello.action?inner&fixed

 

霍霍,浏览器乖乖的跳转到了error.jsp页面,整个世界清静了......

 

场景分析

如果列为看官大大能坚持看到这里,不妨再看一下解难场景下的时序图:




 

这应该才是难经3:Struts2,拦截器拦不住Result?问题的最终解。

  • 大小: 160.3 KB
  • 大小: 157.5 KB
  • 大小: 153.1 KB
  • 大小: 163.9 KB
  • 大小: 62.4 KB
分享到:
评论
9 楼 guduyishuai 2014-04-22  
太牛了,膜拜
8 楼 glyphvectory 2013-05-22  
大神,我现在也是出现这个问题,它报错后不跳转到我指定的页面,我是捕获到了错误,但是就是不跳转页面。

能不能说说,解难具体是怎么解决的。在那个类。后面我还会古来看看。谢谢你了
7 楼 lixueyong87 2013-03-12  
6 楼 lixueyong87 2013-03-12  
强人!!!
5 楼 ldw1228 2013-01-10  
时序图很是清晰,楼主
4 楼 happysnowcity 2012-12-26  
强人!!!
3 楼 sxgkwei 2011-09-16  
持续关注强人中。。。
2 楼 feizhouyu 2010-09-15  
厉害!
1 楼 yjhexy 2009-12-05  
强人!!!

相关推荐

    难经3:Struts2,拦截器拦不住Result?

    标题中的“难经3:Struts2,拦截器拦不住Result?”揭示了这是一个关于Struts2框架中拦截器(Interceptor)与结果(Result)交互问题的讨论。在Struts2框架中,拦截器是实现业务逻辑和控制逻辑之间解耦的重要机制,而...

    先秦至三国时期的医学文献.docx

    这些文献指出,胃脉异常可能导致不卧,并与其他病症如消瘦、多尿、脚肿、关节疼痛等症状联系在一起,预示着严重的健康问题。 2. 《内经》:《内经》是中医理论的重要基础,其中多次提到与睡眠相关的疾病,如“不得...

    2019年安徽屯溪区个体经济发展服务中心招聘模拟试题及答案解析.docx

    9. 视频播放技术:在 CPU 主频较低的计算机上播放 VCD 或 DVD 光盘,可能需要借助解压缩技术,如硬件解码器或软件解码器,以减轻CPU的负担,保证视频流畅播放。 这些知识点涵盖了法律、化学、法学、中医、经济学、...

    中医研修会10月份工作计划.doc

    2. 专题讲座:邀请知名中医专家进行《难经》的专题讲解,解析其独特的脏腑理论和脉象学说。 3. 实践培训:以《伤寒杂病论》为基础,进行辨证论治的实践操作训练,提高临床应对复杂病症的能力。 4. 案例分享:会员...

    中医诊断学复习要点.doc

    - 了解中医诊断学在历史上的发展,包括代表性的医家和他们的著作,如《难经》、《伤寒杂病论》等。 6. **具体内容**: - 问诊:包括问寒热、问汗、问疼痛、问头身胸腹、问耳目、问睡眠、问饮食口味、问二便、问经...

    2016年上半年浙江省医疗卫生招聘公共基础知识考试题.pdf

    5. 自发感觉异常:无外界刺激但有蚁行感,可能表现为感觉异常,这可能是神经系统疾病的症状。 6. 下颌中切牙的鉴别:通过牙根远中面的长形凹陷等特征来判断左右。 7. 清虚热兼有利尿通淋功效的药物:白薇具有这样...

    主治医师 (中医全科学)-肺系病证(A1型题 2).doc

    ### 主治医师 (中医全科学)-肺系病证(A1型题 2) #### 喘证发病机制 - **选项解析**: - A. 心和肺:不符合喘证的主要发病机理。 - B. 肝和脾:与喘证发病关系较小。 - C. 肺和脾:虽涉及肺脏但未涵盖肾脏在喘证...

    2022年中医执业医师考试复习资料完全版归纳.docx

    8. **癫狂**:出自《内经》,区分“癫”与“狂”的依据为《难经》,“重阴者癫”、“重阳者狂”。 以上知识点涵盖了中医执业医师考试中关于感冒、咳嗽、哮与喘以及其他病症的重要理论与实践内容,有助于考生全面...

    《中医学基础》试题及参考答案(中医学本科).doc

    【知识点详解】 1. 十二经脉流注次序:...1. 《难经》 2. 整体观念,辨证论治 3. 心,脏腑,自然环境,社会环境 4. 生理之本,生命之动力,生命之主宰 【判断题】 1. 正确 2. 正确 3. 正确 4. 文档缺失,无法判断

    针灸学习题集(已排版).doc

    4. 针灸医学史上的三次大总结可能指的是《内经》的初步总结、《难经》的补充和完善以及《针灸甲乙经》的系统整理。 六、论述题涉及的知识点: 1. 针灸的起源可能追溯到新石器时代,随着石针的发现,逐渐发展为成熟...

    胡希恕金匮要略讲座.docx

    7. 《难经》的理论借鉴:治疗思路受到《难经》的影响,如“西方实、东方虚,补南方、泻北方”的原则,通过调整心火和肾水的关系,以达到治疗目的。 这些知识点展示了中医临床诊疗的独特观念和方法,强调了整体观念...

    精品资料(2021-2022年收藏)浙江省医疗卫生招聘公共基础知识考试试题.docx

    2. 亡阴症状:主要表现为手足虽温而大汗不止,与选项B对应。亡阴通常发生在病情严重、体质虚弱的患者身上。 3. 地方性氟病的防治:主要通过改良水质,去除水源中的氟,预防氟中毒。 4. 高血压的诊断标准:按照世界...

    中医执业医师考试模拟预测题及答案.docx

    - **知识点**:“邪扶生气而来,虽进而易退”这句话出自《难经》,指的是当邪气侵入人体时,如果侵犯的是与其相生的脏腑,则邪气虽能入侵,但容易被清除。这体现了五行之间的**相生关系**。根据题意,这里的“邪扶...

    中医基础理论练习总习题.doc

    2. **中医学的根本特点**:主要体现在整体观念、辨证论治和预防为主等方面,强调人体与自然环境的和谐统一,疾病治疗注重个体差异。 3. **中医学理论体系的形成条件**:古代哲学思想、实践经验、古代科学技术的发展...

    2019浙江余杭区仁和街道招聘巡防队员试题及答案解析.docx

    ### 2. 文物保护措施 - **控制污染排放**:严格限制附近二氧化硫和氮氧化物的排放,以减少对石质文物的腐蚀。 - **表面涂覆保护层**:在石雕、石刻及建筑物表面涂盖防护层或保护膜,以抵御外界环境的影响。 - **不...

    南通大学2019年招聘模拟试题及答案解析.docx

    2. 政府与事业单位的关系:事业单位是国家设置的公益性质机构,它们与政府之间的关系不是直接的行政隶属关系,而是一种法制化的契约关系。政府通过法规和政策对事业单位进行指导和监管,同时给予一定的财政补贴,...

    山东省枣庄市2012年秋七年级历史上册《第8课中华文化的勃兴(一)》教案 新人教版.doc

    - **金文**:出现在商周时期的青铜器上,是铭文的一种,提供了研究古代社会的重要资料。 - **大篆**:西周晚期到秦朝初期广泛使用的文字,是小篆的前身,对汉字的规范化发展有着重要作用。 2. **《诗经》和屈原**...

    2019浙江卫视招聘综艺、采编、营销等专业人员试题及答案解析.docx

    2. 组织结构与管理:扁平化组织结构是现代企业与政府组织的发展趋势,旨在减少管理层级,增加行政幅度,提高员工积极性,增强组织灵活性和效率,降低成本。然而,扁平化结构也可能导致权力分散,控制力减弱。 3. ...

Global site tag (gtag.js) - Google Analytics