Struts2中prepare方法抛出异常时如何保证Action方法正常执行
Struts2 prepare方法异常不阻断Action执行的优化方案
你的核心思路是对的:必须在prepare方法里捕获所有异常,避免异常向外抛出到拦截器层,才不会跳过后续的Action方法调用,现有实现可以从复用性、可维护性角度做进一步优化,不需要每个Action都单独写异常存储和判断逻辑:
方案1:抽取公共BaseAction统一处理(最常用)
把异常存储、prepare异常捕获的逻辑抽到公共父类,所有业务Action继承即可,不需要每个业务类重复写模板代码:
public abstract class BaseAction extends ActionSupport implements Preparable { // 存储prepare阶段抛出的异常 private Exception prepareException; @Override public final void prepare() throws Exception { try { // 子类实现具体的prepare业务逻辑 doPrepare(); } catch (Exception e) { this.prepareException = e; } } /** * 子类重写这个方法实现原本的prepare逻辑 */ protected abstract void doPrepare() throws Exception; /** * 供子类Action方法调用,抛出prepare阶段存储的异常 */ protected void throwIfPrepareFailed() throws Exception { if (prepareException != null) { throw prepareException; } } }
业务Action使用方式:
public class MyBusinessAction extends BaseAction { @Override protected void doPrepare() throws Exception { // 原来的prepare逻辑,不需要自己加try-catch // ... } @Action("myMethod") public String myMethod() { try { // 直接调用父类方法判断prepare是否有异常 throwIfPrepareFailed(); // 业务逻辑 // ... } catch (Exception e) { // 统一处理异常,包括prepare阶段抛出的 // ... } finally { // ... } return SUCCESS; } }
方案2:自定义拦截器统一处理(零侵入业务代码)
如果不想改现有Action的继承结构,可以自定义拦截器,放在默认的PrepareInterceptor之后、Action执行之前,统一捕获prepare阶段的异常:
public class PrepareExceptionHolderInterceptor extends AbstractInterceptor { @Override public String intercept(ActionInvocation invocation) throws Exception { Object action = invocation.getAction(); if (action instanceof Preparable) { try { ((Preparable) action).prepare(); } catch (Exception e) { // 异常存到上下文,不抛出,继续执行Action ActionContext.getContext().put("prepareException", e); } } return invocation.invoke(); } }
之后在struts配置里把这个拦截器加到你的拦截器栈中,替换原有默认的prepare拦截器即可,Action方法里直接从上下文取异常使用,不需要每个Action单独定义成员变量。
注意事项
- 不要在prepare方法里捕获
Error类型的Throwable,这类系统级错误比如OOM本来就应该终止流程,不需要继续执行Action - 如果prepare阶段的异常不需要在Action方法里单独处理,也可以在捕获后直接存到请求上下文,放到统一的全局异常处理逻辑里消费
内容的提问来源于stack exchange,提问作者Lof
相关产品推荐
相关产品推荐

