多层容错架构强调通过隔离、封装和契约控制保障 getter 失效时不中断主流程;禁止在 getter 中执行非幂等操作、调用可重写方法,应改用 computexxx() 命名;推荐 supplier 注入、不可变数据载体、optional 包装、防御性降级及编译期静态检查。

多层容错架构不是靠“加更多层”来防崩溃,而是通过隔离、封装和契约控制,让 Getter 在继承链中失效时不影响主流程。关键不在“怎么调用”,而在“谁负责校验、谁承担失败”。
Getter 不该承担业务逻辑或状态依赖
很多崩溃源于在 getter 中执行了非幂等操作(如远程调用、集合遍历、空指针解引用)或隐式依赖未初始化字段。Java/Kotlin/Scala 等语言中,getter 是访问属性的“门面”,不是执行入口。
- 避免在 getter 内做 lazy 初始化以外的副作用操作(例如:首次调用才查数据库)
- 禁止在 getter 中调用可被子类重写的方法——父类构造期间子类方法可能尚未就绪
- 若需计算逻辑,应显式命名为
computeXxx()或resolveXxx(),与访问器语义区分开
用不可变契约替代运行时继承暴露
当多个子类共用一个父类 getter,而子类可能覆盖字段或改变初始化顺序时,最稳妥的方式是切断“字段直读”路径,转为统一契约接口。
- 父类声明
protected final Supplier<string> displayNameSupplier</string>,由子类在构造时注入,getter 只做安全委托:return displayNameSupplier.get() - 使用 record 或 @Value(Lombok)定义只读数据载体,避免继承带来的字段遮蔽风险
- 对可能为 null 的返回值,统一用
Optional<t></t>包装,强制调用方处理空场景
引入防御性包装与降级兜底
即使 getter 本身轻量,上游调用链也可能因 NPE、ClassCastException 或并发修改抛异常。此时不能让异常穿透到 UI 或 RPC 层。
- 在服务层或 DTO 转换层统一拦截 getter 异常,转为日志 + 默认值(如空字符串、0、空集合)
- 对关键展示字段,使用类似
SafeAccessor.of(obj).get("name", "未知")的工具类封装,内部捕获RuntimeException并降级 - Spring 环境下可用
@ExceptionHandler拦截NullPointerException等底层异常,但更推荐前置防御而非事后兜底
编译期与静态检查提前拦截隐患
很多 getter 崩溃其实在编码阶段就能发现,比如子类覆盖了父类同名字段导致遮蔽、或 Lombok @Data 与继承混用引发 toString() 循环调用。
- 启用
-Xlint:serial和-Xlint:varargs,部分 IDE(如 IntelliJ)会标出 “shadowed field” 警告 - 禁用 public 实例变量,全部改为
private+ 显式 getter/setter,消除字段直接访问带来的不确定性 - 在 CI 流程中加入 NullAway 或 ErrorProne 插件,强制要求所有 getter 返回值标注
@Nullable或@NonNull










