acl中应使用throws声明自定义的受检异常(如aclintegrationexception),而非暴露外部依赖的原始异常;需在acl实现内捕获并转换sqlexception、httpclienterrorexception等为本域语义一致的异常,确保业务层隔离技术细节。

在防腐层(ACL)中使用 throws 声明受检异常时,核心原则是:**不把外部系统/下游模块的原始异常直接暴露给上游业务层,而是统一转换为本域可理解、可处理的异常类型**。Java 的受检异常(checked exception)必须显式声明或捕获,而 ACL 正是做“协议翻译”和“异常语义隔离”的关键边界。
明确 ACL 的异常职责边界
ACL 本质是适配器,它封装对外部服务(如第三方 API、遗留系统、数据库驱动等)的调用。这些依赖往往抛出与其技术栈强绑定的异常(如 SQLException、HttpClientErrorException、RemoteAccessException),这些异常对业务层无业务含义,且违反领域内聚性。
- ACL 内部可以
throws受检异常,但仅限于 ACL 自定义的、与本上下文语义一致的异常(如ThirdPartyServiceUnavailableException) - 原始依赖的受检异常必须在 ACL 实现内部被捕获,并转换为 ACL 层自己的异常体系
- 转换后的异常应继承自
RuntimeException(非受检)或统一的受检异常基类(如DomainIntegrationException),取决于团队对异常传播策略的约定
推荐做法:定义 ACL 专属异常基类 + 转换逻辑
避免直接抛出 IOException 或 SQLException,而是建立清晰的异常映射:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 定义一个 ACL 层专用的受检异常基类(例如
AclIntegrationException),所有 ACL 对外声明的异常都继承它 - 在 ACL 方法签名中用
throws AclIntegrationException明确契约,而非暴露底层异常 - 在方法体内用
try-catch捕获原始异常,按错误语义分类转换:
• 网络超时 →new AclIntegrationException("第三方服务响应超时", e)
• HTTP 404 →new AclIntegrationException("外部资源不存在", e)
• 数据库连接失败 →new AclIntegrationException("集成服务不可用", e)
配合 throws 使用的典型代码结构
以下是一个典型的 ACL 接口及其实现示例:
// ACL 接口 —— 只声明领域友好的异常
public interface PaymentGatewayAcl {
PaymentResult submitPayment(PaymentRequest request) throws AclIntegrationException;
}
// ACL 实现 —— 封装原始调用并转换异常
public class StripePaymentAclImpl implements PaymentGatewayAcl {
@Override
public PaymentResult submitPayment(PaymentRequest request) throws AclIntegrationException {
try {
// 调用 Stripe SDK(可能抛出 StripeException,是受检异常)
StripeCharge charge = stripeClient.charge(request.toStripeParams());
return PaymentResult.success(charge.getId());
} catch (StripeException e) {
// 统一转换为 ACL 层异常,隐藏 Stripe 细节
throw new AclIntegrationException("支付网关调用失败", e);
}
}
}
这样上游业务服务只需处理 AclIntegrationException,无需了解 Stripe 的异常体系,也符合防腐层“隔离变化”的设计初衷。
是否该保留 throws?取决于 ACL 的调用方契约
如果 ACL 被领域服务同步调用,且团队约定集成异常必须显式处理,则保留 throws 是合理选择;若希望进一步解耦(如通过事件或回调异步集成),也可将 ACL 异常转为非受检异常(RuntimeException 子类),由上层统一兜底处理。
- 保留
throws:适合强一致性场景,强制调用方考虑失败路径 - 转为非受检异常:适合最终一致性或监控告警优先的场景,减少模板代码
- 无论哪种,关键点不变:ACL 内部完成转换,不泄漏外部异常细节
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










