模板方法模式通过在父类中固定异常处理流程,使子类专注业务逻辑;它与@controlleradvice分层协作,前者归一化可预期业务异常,后者兜底未捕获的系统异常。

模板方法模式本身不负责异常拦截,但它天然适合把异常处理逻辑“固定”在模板骨架里,让子类专注业务,不用重复写 try-catch。真正实现统一拦截的,是 Spring 的 @ControllerAdvice 或自定义基类中的统一出口——模板方法只是把“哪里抛、怎么抛、谁来收”这条链路组织得更清晰。
模板方法如何结构化异常抛出
在控制层或服务层抽象出模板基类,把流程拆成“准备→执行→收尾”,其中“执行”是抽象方法,由子类实现;而异常统一在模板方法的 catch 块中捕获并封装,不交给子类处理。
- 子类只写核心逻辑,比如
doBusiness(),遇到业务规则冲突直接throw new BusinessException("库存不足") - 父类模板方法用
final定义流程:先校验参数 → 调用doBusiness()→ 成功则封装结果,失败则捕获所有异常并转为标准响应 - 避免子类在
doBusiness()中自行 try-catch 吞异常,否则父类收不到,统一处理就失效
与 Spring @ControllerAdvice 协同工作
模板方法管“本类内”的异常归一化,@ControllerAdvice 管“整个 Web 层”的异常兜底。两者不是替代关系,而是分层配合:
- 模板基类处理的是本模块内可预期的业务异常(如参数校验失败、状态不匹配),返回 HTTP 200 + 自定义 code
- @ControllerAdvice 拦截未被基类捕获的异常,比如
NullPointerException、SQLException,记录日志并返回 500 错误码 - 注意:@ExceptionHandler 方法参数要按具体异常类型声明(如
@ExceptionHandler(BusinessException.class)),不要只写Exception,否则会覆盖更细粒度的处理
关键细节:什么该抛、什么不该捕
不是所有异常都适合放进模板方法统一收口,要区分异常性质:
- 业务异常(
BusinessException、ParamException):必须向上抛,交给模板或全局处理器,前端需要明确提示 - 程序 Bug 类异常(
NullPointerException、ArrayIndexOutOfBoundsException):不建议在模板里 catch,应让其快速失败,靠监控告警发现并修复 - 受检异常(
IOException、SQLException):在模板方法内可转换为运行时异常再抛出,避免子类强制处理;或由基类用 try-with-resources 封装资源操作,内部消化 I/O 异常
一个轻量级模板基类示例
不依赖 Spring 也能落地,适用于传统 Servlet 或 Struts Action 场景:
- 定义抽象基类
BizTemplateAction,含final execute()方法 -
execute()内部调用validate()(具体校验)、doAction()(子类实现)、renderResult()(统一输出 JSON) - 所有异常统一 catch,判断类型后设置
result.code和result.message,最后 return - 子类只需继承,重写
doAction(),无需关心异常格式化和响应包装
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











