【问题标题】:Can JMX operations take interfaces as parameters?JMX 操作可以将接口作为参数吗?
【发布时间】:2012-06-26 09:55:34
【问题描述】:

我在使用 MBean 作为参数时遇到问题。如果我尝试使用代理对象通过 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)

它似乎试图使用实际的实现类而不是接口,并且不检查这是否是所需接口的子接口。扩展类也会发生同样的事情(例如声明HashMap,传入LinkedHashMap)。这是否意味着不可能为这些方法使用接口?目前我正在通过更改方法签名以接受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;
    }
}

【问题讨论】:

  • 你好雷神;你能提供创建你的代理对象的代码吗?
  • 我正在使用内部实用程序类,坦率地说,我不确定我是否真的能弄清楚其中发生了什么(它正在做大量与安全相关的额外事情,而不是我见过的最好的书面代码),但我会尝试提取重要的部分并将它们添加到帖子中。

标签: java jmx mbeans


【解决方案1】:

知道了。 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 的实际具体对象,因此您永远不会使用参数本身的直接类型进行匹配。 (出于同样的原因,原语也会出现类似的问题)。

请参阅此blog post,以“制作 MetaMBean 的一个棘手部分”开头的段落开头,因为它解释了这个问题(或我认为你遇到的问题)更详细一点,但MBeanServer[Connection] 的invoke 方法是:

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

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

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

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

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

【讨论】:

  • 一个非常有趣且经过深思熟虑的答案。谢谢。我现在很难尝试,因为这门课在不同的项目中,而且我被赋予了优先处理的问题。现在,我将对您的答案投赞成票,因为在我看来这可能是正确的,一旦有机会,我会回复您是否可以通过这种方式解决它。非常感谢。
猜你喜欢
  • 2020-07-12
  • 2013-10-15
  • 2011-01-24
  • 1970-01-01
  • 1970-01-01
  • 2020-10-27
  • 2013-08-09
  • 2016-12-17
  • 1970-01-01
相关资源
最近更新 更多