如何安全地处理JMX远程客户端中缺少的本地类

时间:2013-01-16 12:36:08

标签: websphere rmi jmx classnotfoundexception corba

我一直在使用编程远程JMX客户端,连接到WebSphere Application Server的MBean服务器。到目前为止,我可以使用适当的JMXServiceURL进行连接并订阅来自我的bean的通知。

但是 - 如果一个bean发送的通知包含一个不在我的本地类路径上的类,那么它会有一个很好的堆栈跟踪:

SEVERE: Failed to fetch notification, stopping thread. Error is: java.rmi.RemoteException: CORBA NO_IMPLEMENT 1330646337 No; nested exception is: 
    org.omg.CORBA.NO_IMPLEMENT: The sender's class RMI:com.mycompany.MyWeirdClass:143EC4C84209B825:EAD08F0965BC6044 is not present on the local classpath, and the class is not marked as truncatable, so it cannot be unmarshaled.  vmcid: OMG  minor code: 1  completed: No
java.rmi.RemoteException: CORBA NO_IMPLEMENT
... more frames ...

最终由以下原因引起:

Caused by: java.lang.ClassNotFoundException: com.mycompany.MyWeirdClass
    at com.ibm.rmi.util.RepositoryId.loadClass(RepositoryId.java:675)
    at com.ibm.rmi.util.RepositoryId.checkClassCache(RepositoryId.java:644)
    ...

看起来它在IBM的代码中深入爆发,似乎没有任何地方我可以做任何事情;有问题的通知永远不会到达我的NotificationListener。

因此;如果不阻止我接收进一步的通知,我该怎么办才能处理这种情况?

1 个答案:

答案 0 :(得分:3)

我可以想出4种解决这个问题的方法,按复杂度递增顺序(我认为):

将类库添加到客户端类路径

陈述显而易见,但试图全面。

修改通知

考虑修改服务器生成的通知,将 com.mycompany.MyWeirdClass 实例交换为格式化字符串。如果对象很复杂,请考虑使用XML或JSON。如果您可以修改通知发件人来封送实例,那可能是最简单的。如果没有,你可以修改 com.mycompany.MyWeirdClass 类(应该是Serializable,对吗?)并添加一个返回实例的String表示的writeReplace方法

远程ClassLoader

在WebSphere应用程序中实现一个HTTP服务器,该服务器返回包含 com.mycompany.MyWeirdClass 类及其所有依赖项的JAR。 (从技术上讲,HTTP服务器可以在任何地方,只要它提供正确的类。)让我们假设JAR可以在 http://classloader.mycompany.com/Weird.jar 获得即可。现在使用添加的系统属性启动您的客户端,如下所示:

java .....  -D-Djava.rmi.server.codebase=http://classloader.mycompany.com/Weird.jar ...

有一个HTTP服务器实现的示例,用于提供动态类加载here

将类实现为JMX OpenType

最常见的方法是将课程设为MXBean,或者您可以实施CompositeData或扩展CompositeDataSupport。如果您不介意使用 com.sun 类,则java运行时(1.6+)包含DefaultMXBeanMappingFactory,它将为您创建复合数据实例,因此这个有用的实用程序可用于与上述解决方案之一的音乐会。例如,您可以像这样实现 writeReplace 轨道:

import com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory;
import com.sun.jmx.mbeanserver.MXBeanMapping;
final MXBeanMapping mapping = 
   DefaultMXBeanMappingFactory.DEFAULT.mappingForType(
      com.mycompany.MyWeirdClass.class, 
      DefaultMXBeanMappingFactory.DEFAULT
   );
private Object writeReplace() throws ObjectStreamException {
   try {
      return mapping.toOpenValue(this);
   } catch (Exception ex) {
      throw new RuntimeException(ex);
   }
}