notserializableexception 的根源在于对象字段中存在不可序列化类型,需定位堆栈顶的类名,检查非static非transient字段及其嵌套结构,对日志器等用transient标记,必要时在readobject()中重建。

遇到 NotSerializableException,别急着改主类加 implements Serializable——异常真正卡住的地方,往往藏在某个字段里。
看准堆栈顶行的“第一个失败类型”
异常消息中明确写出的类名(比如 org.slf4j.Logger、java.lang.Thread、com.alibaba.cloud.analyzer.MetricsClient),就是序列化器实际碰到的第一个不可序列化类型。它不一定是你调用 writeObject() 的那个对象,而是这个对象里某个字段的类型。
- 打开异常堆栈,直接定位最上面那行
java.io.NotSerializableException: xxxxx - 如果报的是
java.util.Date,基本不用管(它本身可序列化);但报DateTimeFormatter或SimpleDateFormat就要处理 - Spring 注入的
ApplicationContext、Guava 的Cache、Logback 的LoggerContext都是高频“雷区”
检查字段及其嵌套结构
一个类实现了 Serializable,不代表它安全。只要任意一层字段(包括 List 元素、Map 的 value、内部类实例、甚至 Lambda 捕获的对象)含不可序列化类型,就会爆。
- 逐个检查类中所有非
static、非transient字段的类型声明 - 特别注意集合类里存的对象:比如
List<myentity></myentity>中的MyEntity有Logger字段,问题就出在这里 - 匿名内部类、非静态内部类会隐式持有外部类引用,若外部类不可序列化,整个链路都失效
快速止血:用 transient 跳过非必要字段
对运行期动态生成、无需持久化的字段(如日志器、连接池引用、回调函数、线程局部变量),加 transient 是最快生效的方案。
- 加上后,该字段不再参与序列化,反序列化时为
null(引用)或默认值(基本类型) - 不要给
final字段加transient——它无法在readObject()中重新赋值 - 常见可标记字段:
private transient Logger logger、private transient ThreadPoolExecutor executor
必要时手动重建 transient 字段
如果字段虽不序列化但业务上必须存在(比如 logger、objectMapper),可在 readObject() 中主动重建:
- 方法内必须先调用
in.defaultReadObject(),完成默认反序列化流程 - 只适用于非
final字段;重建逻辑应轻量,避免耗时操作或依赖外部环境(如建数据库连接) - 示例:
this.logger = LoggerFactory.getLogger(getClass());
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











