JBoss EAP7.4集群中序列化导入Log类的问题求助
JBoss EAP 7.4集群会话序列化日志组件问题解决
问题场景
在JBoss EAP 7.4集群运行Java应用时,序列化会话数据遇到日志组件相关的序列化错误。现有代码结构如下:
package com.company.myapp.bean.common; import java.io.Serializable; import com.company.jfoundation.log.Log; public abstract class myappBaseBean extends BaseBean { public String moduleItemAction() { // ... 业务逻辑 if (Log.ON) { this.log.fine("********* MODULE ITEM ACTION INVOKED **********"); } Map<String, String> requestParamMap = FacesContext.getCurrentInstance().getExternalContext() .getRequestParameterMap(); String moduleItemName = requestParamMap.get("itemName"); String beanName = requestParamMap.get("beanName"); if (Log.ON) { this.log.fine("moduleItemName---> " + moduleItemName); this.log.fine("beanName---> " + beanName); } // ... 业务逻辑 } @SuppressWarnings("rawtypes") protected List<ScreenDTO> fetchScreenList( String modCode) { Collection screenList = null; try { this.adminBI = this.getAdminService(); } catch ( ServiceLocatorException sLocatorExp) { this.setError(true); this.setSuccess(false); new ErrorHandler(sLocatorExp, this.resourceBundle); this.log.error(this.getClass().getName(), "", sLocatorExp); } // ... 业务逻辑 return null; } }
尝试让父类实现Serializable接口:
import java.io.Serializable; public abstract class myappBaseBean extends BaseBean implements java.io.Serializable { }
但仍出现以下序列化错误:
18:28:04,506 WARN [org.infinispan.PERSISTENCE] (default task-18) ISPN000559: Cannot marshall 'class org.infinispan.marshall.protostream.impl.MarshallableUserObject': java.io.NotSerializableException: com.company.jfoundation.log.Log at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:278) at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1182) at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:1140) at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:1119) at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:1119) at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:271) at org.jboss.marshalling.AbstractObjectOutput.writeObject(AbstractObjectOutput.java:58) at org.jboss.marshalling.AbstractMarshaller.writeObject(AbstractMarshaller.java:111)
核心疑问:有没有快速方法序列化导入的Log模块?还是需要大量重构?能否在导入时标记任意模块为可序列化?
问题分析
错误根源是:myappBaseBean中持有的log实例字段属于com.company.jfoundation.log.Log类,而该类未实现Serializable接口。仅让myappBaseBean实现Serializable没用,因为Java序列化会递归序列化所有非transient的成员变量,只要其中一个不支持序列化就会报错。
快速解决方案(无需大量重构)
1. 标记log字段为transient(推荐)
日志对象不属于会话状态,完全不需要序列化。在myappBaseBean中声明log字段时添加transient修饰符:
private transient com.company.jfoundation.log.Log log;
序列化时会自动跳过该字段,避免报错。反序列化后,可通过以下方式重新初始化log对象:
- 在bean的
readObject方法中手动初始化:private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); // 替换为你实际获取log实例的逻辑 this.log = Log.getInstance(this.getClass()); } - 或者用懒加载方式,在需要使用log时再初始化(比如在
moduleItemAction方法中先判断log是否为null,再初始化)。
2. 自定义序列化逻辑(特殊场景)
如果因特殊需求必须处理log的序列化,但无法修改com.company.jfoundation.log.Log的源码,可让myappBaseBean实现Externalizable接口,手动控制序列化过程:
public abstract class myappBaseBean extends BaseBean implements Externalizable { // ... 原有业务代码 @Override public void writeExternal(ObjectOutput out) throws IOException { // 仅序列化会话相关的必要字段,比如状态标记、业务数据 out.writeBoolean(this.isError()); out.writeBoolean(this.isSuccess()); // 按需添加其他需要序列化的字段 } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { // 反序列化恢复业务字段 this.setError(in.readBoolean()); this.setSuccess(in.readBoolean()); // 恢复其他业务字段 // 重新初始化log对象 this.log = Log.getInstance(this.getClass()); } }
关于“导入时标记任意模块为可序列化”
完全不可能。Java的序列化机制要求类本身必须实现Serializable或Externalizable接口,这是类的固有属性,与导入语句无关。导入仅用于告知编译器类的位置,无法通过导入操作修改类的序列化能力。若无法修改第三方类的源码,只能通过上述两种方式绕开。
内容的提问来源于stack exchange,提问作者Mr. E
相关产品推荐
相关产品推荐

