我遇到以MBean
作为参数的Map<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)
它似乎尝试使用实际的实现类而不是接口,并且不检查它是否是所需接口的子级。扩展类也会发生同样的事情(例如声明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;
}
}
答案 0 :(得分: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的一个棘手部分”开头的段落开头看这个blog post,因为它解释了这个问题(或者我认为你遇到的问题)更详细一点,但invoke [连接]的MBeanServer方法是:
invoke(ObjectName name, String operationName, Object[] params, String[] signature)
前两个和最后一个参数是导航的,它们确切地指定应该调用在服务器中发布的所有操作中的哪个操作。避免此问题的最佳方法是避免必须“猜测”签名并仅依赖于ObjectName和操作名称,而后者又可以通过询问(并可能缓存)MBeanInfo和{{ 3}}目标MBean。 MBeanOperationInfos将为您提供签名,因此您无需猜测。
如果确实是您的问题,可以通过以下几种方式解决问题:
我希望这会有所帮助。如果事实证明这不是根本原因,那就忘记我说了什么......