使 subclass 序列化为 super class 的实例?

make subclass serialize as an instance of the super class?

我正在处理具有构建 MBean 的代码库(用于导出到 jmx)。

原始代码只是构建了一个 MBeanInfo 实例:

@Override
public MBeanInfo getMBeanInfo() {
    MBeanAttributeInfo[] attrs = //SLOW TO BUILD
    return new MBeanInfo(...attrs...);
}

因为 mbean 属性的构建成本很高,而且这个方法被调用得相当频繁(即使没有附加 jmx 客户端),我已经尝试创建一个 MBeanInto 的子class 来懒惰地计算这些属性:

public class LazyMBeanInfo extends MBeanInfo implements Externalizable {
    private transient AttributeCallback callback = null;
    private volatile MBeanAttributeInfo[] lazyAttrs = null;

    public LazyMBeanInfo(...AttributeCallback callback...) throws IllegalArgumentException {
        super(className, description, null, constructors, operations,   notifications);
        this.callback = callback;
    }

    @Override
    public MBeanAttributeInfo[] getAttributes() {
        MBeanAttributeInfo[] val = lazyAttrs;
        if (val != null) {
            return val.clone(); //match upstream behaviour
        }
        if (callback == null) {
            throw new IllegalStateException("BUG");
        }
        val = callback.buildAttributes();
        if (val == null) {
            val = new MBeanAttributeInfo[0];
        }
        lazyAttrs = val;
        return val.clone();
    }

    public interface AttributeCallback {
        MBeanAttributeInfo[] buildAttributes();
    }
}

问题 是 JMX(通过 RMI)序列化 MBeanInfo 对象,然后在 jconsole(或 jvisualVM)中出现错误:

所以 - 我能以某种方式实现 Externalizable 并将自己序列化为父 class 的实例吗?理想情况下,我希望它能工作:

public class LazyMBeanInfo extends MBeanInfo implements Externalizable {
    //same as before, plus:
    @Override
public void writeExternal(ObjectOutput out) throws IOException {
        MBeanInfo vanilla = new MBeanInfo(...);
        out.writeObject(vanilla);
    }
}

但事实并非如此。

这可能吗?

除非您使用 [高度动态] DynamicMBean,否则我不明白为什么每次调用 getMBeanInfo() 都需要重建 MBeanInfo,但是....

您的 LazyMBeanInfo 可以正常工作(尽管我还没有测试过这个具体案例)。 MBeanInfo 已经实现了 Serializable,所以您希望序列化过程写出 MBeanInfo,而不是 LazyMBeanInfo,因为客户端可能在其 class 路径中没有那个 class。但是,LazyMBeanInfo 可以实现这个方法:

Object writeReplace() throws ObjectStreamException;

此时您写出底层 MBeanInfo。请参阅 Serializable JavaDoc,特别是:

Serializable classes that need to designate an alternative object to be used when writing an object to the stream should implement this special method with the exact signature:

ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;

那样的话,实际的对象可以是 LazyMBeanInfo 的一个实例,但是您写出的内容可以是一个实际的 MBeanInfo,它是从缓存的 lazyAttrs 构建的。

话虽如此,但我不会实施首次调用时构建的方法,而是通过在首次创建 MBean 时或在创建 MBean 时简单地构建完整的 MBeanInfo 来实施首次使用前构建已经注册。然后 return 每次 getMBeanInfo() 调用时的预构建 MBeanInfo。

要在 MBean 注册时执行此操作,请实施 MBeanRegistration interface, and build the cached MBeanInfo in the postRegister 方法。