2

我正在尝试创建一个 MXBean 操作,该操作将返回一个没有属性的抽象类型(实际类型及其属性将在运行时确定)。我的数据模型可以简单地说如下:

public interface I extends CompositeDataView {
    // empty
}

public final class A implements I {
    private final String foo;

    @ConstructorProperties({"foo"})
    public A(final String foo) {/* ... */}

    public String getFoo() {/* ... */}

    @Override
    public CompositeData toCompositeData(CompositeType ct) {/* ... */}

    public static A from(final CompositeData cd) {/* ... */}
}

public final class B implements I {
    private final String bar;

    @ConstructorProperties({"bar"})
    public B(final String bar) {/* ... */}

    public String getBar() {/* ... */}

    @Override
    public CompositeData toCompositeData(CompositeType ct) {/* ... */}

    public static B from(final CompositeData cd) {/* ... */}
}

... MXBean 操作签名是:

@MXBean
public interface Baz {
    I f();
}

该操作可以返回 A具有foo属性的实例或具有属性的B实例bar。当然,当NotCompliantMBeanException我尝试注册MBean实例时,我会立即看到一个闪亮的信息:

Caused by: javax.management.openmbean.OpenDataException: Can't map I to an open data type
    at com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory.makeCompositeMapping(DefaultMXBeanMappingFactory.java:458)
    at com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory.makeMapping(DefaultMXBeanMappingFactory.java:292)
    at com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory.mappingForType(DefaultMXBeanMappingFactory.java:257)

似乎我可以用常规MBeans 做一些事情,Serializable但不能用MXBeans 和CompositeDataView. 还是我错了?

4

1 回答 1

1

可以或多或少地做你想做的事,尽管不是那么简单。关键是 MXBean 规范要求 CompositeData 至少有一项。你可以通过在你的基类中拥有一个属性来满足这个要求type,我在AnyCompositeData这里调用了它。该type属性还可以用于决定如何将其转换回CompositeData特定类型,例如 yourFooBar. 在这里的代码中,我把所有东西都塞进了这个AnyCompositeData类,虽然更现实的是它当然是单独的类。我只说明了具体的类Foo,但如何扩展模式以支持其他类应该很明显。

public abstract class AnyCompositeData implements CompositeDataView {
  private final String type;

  public AnyCompositeData(String type) {
    this.type = type;
  }

  public String getType() {
    return type;
  }

  public static AnyCompositeData from(CompositeData cd) {
    switch ((String) cd.get("type")) {
      case "Foo":
        return new Foo((String) cd.get("foo"));
      default:
        throw new IllegalArgumentException("Don't know how to reconstruct: " + cd.get("type"));
    }
  }

  public static class Foo extends AnyCompositeData {
    private final String foo;

    Foo(String foo) {
      super("Foo");
      this.foo = foo;
    }

    public String getFoo() {
      return foo;
    }

    @Override
    public CompositeData toCompositeData(CompositeType ct) {
      try {
        String[] items = {"type", "foo"};
        OpenType<?>[] itemTypes = {SimpleType.STRING, SimpleType.STRING};
        Object[] itemValues = {"Foo", foo};
        CompositeType compositeType = new CompositeType("Foo", "Foo", items, items, itemTypes);
        return new CompositeDataSupport(compositeType, items, itemValues);
      } catch (OpenDataException e) {
        throw new RuntimeException(e);
      }
    }
  }

  @MXBean
  public interface Baz {
    AnyCompositeData f();
  }

  static class BazImpl implements Baz {
    @Override
    public AnyCompositeData f() {
      return new Foo("whatever");
    }
  }

  public static void main(String[] args) throws Exception {
    MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
    ObjectName objectName = new ObjectName("test:baz=baz");
    mbs.registerMBean(new BazImpl(), objectName);
    Baz bazProxy = JMX.newMXBeanProxy(mbs, objectName, Baz.class);
    AnyCompositeData result = bazProxy.f();
    assert result instanceof Foo;
    assert ((Foo) result).getFoo().equals("whatever");
  }
}

如果您有很多类似的子类Foo,那么您可能需要考虑以某种方式使用反射,而不是让该from(CompositeData)方法知道所有子类。

于 2014-12-28T22:03:06.497 回答