You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 22:29:59