0

我遇到了MBean将 aMap<String, Object>作为参数的问题。如果我尝试使用代理对象通过 JMX 执行它,我会得到一个异常:

Caused by: javax.management.ReflectionException
    at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:231)
    at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:668)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
Caused by: java.lang.IllegalArgumentException: Unable to find operation updateProperties(java.util.HashMap)

它似乎试图使用实际的实现类而不是接口,并且不检查这是否是所需接口的子接口。扩展类也会发生同样的事情(例如 declare HashMap、 pass in LinkedHashMap)。这是否意味着不可能为这些方法使用接口?目前我正在通过将方法签名更改为接受 a 来解决它HashMap,但我无法在我的MBeans.

编辑:代理对象是由一个名为JmxInvocationHandler. 它的(希望)相关部分如下:

public class JmxInvocationHandler implements InvocationHandler
{
    ...
    public static <T> T createMBean(final Class<T> iface, SFSTestProperties properties, String mbean, int shHostID)
    {
        T newProxyInstance = (T) Proxy.newProxyInstance(iface.getClassLoader(), new Class[] { iface }, (InvocationHandler) new JmxInvocationHandler(properties, mbean, shHostID));
        return newProxyInstance;
    }
    ...
    private JmxInvocationHandler(SFSTestProperties properties, String mbean, int shHostID)
    {
        this.mbeanName = mbean + MBEAN_SUFFIX + shHostID;
        msConfig = new MsConfiguration(properties.getHost(0), properties.getMSAdminPort(), properties.getMSUser(), properties.getMSPassword());
    }
    ...
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
    {
        if (management == null)
        {
            management = ManagementClientStore.getInstance().getManagementClient(msConfig.getHost(),
                    msConfig.getAdminPort(), msConfig.getUser(), msConfig.getPassword(), false);
        }

        final Object result =  management.methodCall(mbeanName, method.getName(), args ==  null?  new Object[] {} : args);
        return result;
    }
}
4

1 回答 1

2

知道了。JMX 调用有时会成为最好的实用程序类的炮灰.... :)

我怀疑这个人是个问题:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
    {
        if (management == null)
        {
            management = ManagementClientStore.getInstance().getManagementClient(msConfig.getHost(),
                    msConfig.getAdminPort(), msConfig.getUser(), msConfig.getPassword(), false);
        }

        final Object result =  management.methodCall(mbeanName, method.getName(), args ==  null?  new Object[] {} : args);
        return result;
    }

因为 MBean 的操作签名(它不关心继承)是由传递参数的类确定的。由于您无法传递getClass()将返回的实际具体对象,因此java.util.Map您永远不会使用参数本身的直接类型进行匹配。(出于同样的原因,原语也会出现类似的问题)。

请参阅此博客文章,以“制作 MetaMBean 的棘手部分之一”开头的段落开头,因为它更详细地解释了这个问题(或我认为您遇到的问题),但是MBeanServer的调用方法[连接]是:

invoke(ObjectName name, String operationName, Object[] params, String[] signature) 

前 2 个和最后一个参数是导航性的,因为它们准确地指定了应该调用服务器中发布的所有操作中的哪个操作。回避这个问题的最好方法是避免不得不“猜测”签名并且只依赖 ObjectName 和操作名称,而这又可以通过询问(并且可能缓存)目标 MBean的MBeanInfoMBeanOperationInfo来完成. MBeanOperationInfos 将为您提供签名,因此您不必猜测。

如果这确实是您的问题,有几种方法可以解决它:

  1. 如果 MBean 的操作名称是唯一的(即没有重载),那么您可以只使用操作名称来检索 MBeanInfo。
  2. 如果 MBean 的操作被重载(即有多个具有相同名称但参数不同的操作)......但它们都有不同的参数计数,那么您可以通过迭代 MBeanOperationInfos 中所有匹配的操作名称来轻松确定正确的签名和按参数计数匹配。
  3. 如果 #1 和 #2 不适用....那么这很棘手,我将重新评估您的 MBean 代码的方法签名。
  4. 如果 #1 和 #2 不适用且 #3 不符合,请查看Gmx中名为MetaMBean的此类。在最新版本中,它使用 Groovy 创建编译运行时接口,使用 MBean 的 MBeanInfo 使继承(和自动装箱)在方法调用中起作用。相同的方法可以在 JavaScript(其优点是内置于 Java 6+)或其他几种 JVM 脚本语言中实现。或者,看看以前的版本,它试图对已知的操作签名进行模式匹配(实际上工作得很好,但因为我一直在使用 Groovy ......)

我希望这是有帮助的。如果事实证明这不是根本原因,那么忘记我说了什么......

于 2012-07-02T19:38:27.877 回答