сделать сериализацию подкласса как экземпляр суперкласса? - PullRequest
0 голосов
/ 09 июня 2018

я имею дело с кодовой базой, которая имеет сборки MBeans (для экспорта в jmx).

исходный код просто создает экземпляр MBeanInfo:

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

, поскольку атрибуты mbean дороги дляbuild, и этот метод вызывается довольно часто (даже без подключенных 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) я получаю ошибку: enter image description here

так - я могу как-то реализовать 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);
    }
}

но это не так.

Возможно ли это как-нибудь?

1 Ответ

0 голосов
/ 09 июня 2018

Если вы не используете [высоко динамичный] DynamicMBeans, я не понимаю, почему MBeanInfo нужно перестраивать для каждого вызова getMBeanInfo(), но ....

Ваш LazyMBeanInfo может быть сделан дляработать (хотя я не проверял этот конкретный случай).MBeanInfo уже реализует Serializable, так что вы хотите, чтобы процесс сериализации записал MBeanInfo, а не LazyMBeanInfo, поскольку клиент, вероятно, не имеет этого класса в своем пути к классам.Однако LazyMBeanInfo может реализовать этот метод:

Object writeReplace() throws ObjectStreamException;

, после чего вы записываете базовый MBeanInfo.См. Сериализуемый JavaDoc, а именно:

Сериализуемые классы, которым необходимо указать альтернативный объект, который будет использоваться при записи объекта в поток, должны реализовать этот специальный метод с точной подписью:

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

Таким образом, фактический объект может быть экземпляром LazyMBeanInfo, но то, что вы записываете, может бытьфактический MBeanInfo, построенный из ваших кэшированных lazyAttrs.

Сказав, что вместо реализации подхода «сборка при первом вызове» я бы реализовал сборку перед первым использованием, просто создав полную MBeanInfo, когдаMBean сначала создается, или когда MBean зарегистрирован.Затем просто возвращайте предварительно созданный MBeanInfo при каждом вызове getMBeanInfo().

Чтобы сделать это во время регистрации MBean, внедрите интерфейс MBeanRegistration и создайте кэшированный MBeanInfo в postRegister метод.

...