由于自定义异常类,通过JVisualVM在JMX调用中避免ClassNotFoundException

时间:2012-04-20 09:26:54

标签: spring exception jmx jvisualvm

我们的应用程序通过JMX公开了一些方法,我们使用JVisualVM调用它。

这通常很有效,但有时候方法调用会在应用程序内部异常中止。在这种情况下,JVisualVM不显示异常的错误消息,而是显示错误消息

java.rmi.UnmarshalException [...] error unmarshaling return; 
nested exception is: java.lang.ClassNotFoundException [...]

这是无益的,令人困惑的;我们希望JVisualVM显示真正的错误消息。

到目前为止我们发现了什么:

似乎JMX将序列化和反序列化调用期间抛出的任何异常。但是,在我们的例子中,例外是自定义异常,它们不是JDK的一部分。因此,当通过JVisualVM调用方法时,JVisualVM无法显示异常,因为由于未知的自定义异常类而导致反序列化失败。

现在,作为一种解决方法,我们将所有通过JMX公开的方法包装在try-catch块中,而这只是

    throw new RuntimeException("Error invoking method:"+e);

这是有效的,因为它将任何异常转换为字符串,但看起来相当不雅和冗长。

  • 是否有一些通用的方法告诉JMX不要序列化异常?像“总是将异常转换为字符串”之类的东西?
  • 我们使用Spring的MBeanExporter。 Spring中可能有一种机制来处理这个问题吗?

修改

我们知道我们可以配置JVisualVM来加载有问题的类。但是,我们希望JVisualVM在没有特殊配置的情况下工作。此外,它可能运行一个系统,其中应用程序代码甚至不可用。

2 个答案:

答案 0 :(得分:1)

您可以尝试在JVisualVM上使用-Djava.rmi.server.codebase,以便它可以从远程JVM加载异常类吗?

编辑:如果您不想这样做,可以使用方面来执行与try-catch块相同的操作。那你只需要在一个地方。如果你已经使用Spring,那么Spring AOP会非常容易。

答案 1 :(得分:1)

看看java.io.Serializable。您可以实现一个名为writeReplace的可选方法,该方法可以放在自定义异常中。返回原始消息的一般异常。当序列化异常时,它将发送通用。或者您也可以发送一个字符串,但我不确定它是否适用于VisualVM。我想这取决于数据检查的严格程度。

  

需要指定替代对象的可序列化类   在将对象写入流时应该使用它   具有确切签名的特殊方法:

     

ANY-ACCESS-MODIFIER对象writeReplace()抛出   ObjectStreamException;

=====更新=====

知道了。第三方图书馆...... 总结.... 这里的挑战是通过JVisualVM在MBean上调用 setAttribute [s] 调用会导致抛出异常JVisualVM的类路径类型。

如果您在MBeanServer上实现了某种拦截器,它可以捕获任何抛出的异常(可能是任何类名而不是的异常,以 java。 javax。并将它们作为RuntimeExceptions重新抛出,并带有表示原始异常的非常丰富的错误消息。(如果有用,您甚至可以包含堆栈跟踪的字符串呈现)。这基本上就是您正在做的事情现在除了它具有集中在一个地方的优点,并且不依赖于你如何实现你的课程。

虽然标准JMX规范中仍然没有MBeanServer拦截器,但您可以通过创建自己的MBeanServer实现来模仿它们,该实现只是委托给真正的MBeanServer,但对于 setAttribute [s] 调用调用,您可以使用“catch-and-rethrow”技术覆盖。这可能听起来像是大手术,但除了复杂的应用程序服务器JMX实现的棘手问题之外,它实际上相当直接。

请参阅此stackoverflow post和此gist作为示例。

.....话虽如此,您正在使用Spring,您可以指定MBean注册的MBeanServer实例,以及JVisualVM使用的JMXConnectorServer公开的MBeanServer。所以它会更简单:

  1. 使用gist中概述的MBeanServer包装器构思,在Spring中构造它,将真正的MBeanServer注入为委托
  2. 在Spring JMX导出器中引用包装器bean。
  3. 在JMXConnectorServer中引用包装器bean。
  4. 如果您使用自动引导的默认JMXConnectorServer,则需要切换到使用Spring defined one

    基于Spring的方法具有额外的好处,即只有远程MBeanServer调用(如JVisualVM调用)才会遇到异常重写,而应用程序中的内部调用将获得真正的异常,因为它们可以直接转到 real < / em> MBeanServer。

    =====再来一次更新=====

    Spring JMX支持实际上有一个MBean interceptor implementation。 我不知道它,但是当我考虑这个问题时,它听起来就像是Spring会实现的,而且它就是......