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

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

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


由于mbean属性的构建成本很高,并且调用该方法的频率很高(即使未连接jmx客户端),因此我尝试创建MBeanInto的子类来懒惰地计算这些属性:

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)中出现错误:
java - 使子类序列化为父类(super class)的实例?-LMLPHP

所以-我可以以某种方式实现Externalizable并将自己序列化为父类的实例吗?理想情况下,我想这样做:

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);
    }
}


但事实并非如此。

这可能以某种方式吗?

最佳答案

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

可以使您的LazyMBeanInfo正常工作(尽管我尚未测试此特定情况)。 MBeanInfo已经实现了Serializable,所以您需要在序列化过程中写出MBeanInfo而不是LazyMBeanInfo,因为客户端的类路径中可能没有该类。但是,LazyMBeanInfo可以实现此方法:

Object writeReplace() throws ObjectStreamException;


此时,您将写出基础MBeanInfo。请参阅Serializable JavaDoc,特别是:


  需要指定替代对象的可序列化类
  在将对象写入流时应使用此实现
  具有确切签名的特殊方法:
  
  ANY-ACCESS-MODIFIER对象writeReplace()引发
  ObjectStreamException;


这样,实际对象可以是LazyMBeanInfo的实例,但是您写出的内容可以是根据缓存的lazyAttrs构建的实际MBeanInfo。

话虽如此,而不是实现首次调用构建方法,而是通过在首次创建MBean或注册MBean时简单地构建完整的MBeanInfo来实现先使用后构建。然后,只需在每个getMBeanInfo()调用上返回预构建的MBeanInfo。

要在MBean注册时执行此操作,请实现MBeanRegistration接口,并在postRegister方法中构建缓存的MBeanInfo。

关于java - 使子类序列化为父类(super class)的实例?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50768567/

10-12 02:40