Java JMX的用户定义异常

Java JMX的用户定义异常,java,exception-handling,jmx,Java,Exception Handling,Jmx,我通过创建一个MXBean接口和一个实现它的类,在使用JMX的应用服务器中公开了远程管理的方法。此界面中包括用于在我的服务器上设置属性以及获取属性当前值的操作。例如,采取以下方法: public interface WordManagerMXBean { public void addWord(String word); public WordsObject getWords(); public void removeWord(String word); } Wo

我通过创建一个MXBean接口和一个实现它的类,在使用JMX的应用服务器中公开了远程管理的方法。此界面中包括用于在我的服务器上设置属性以及获取属性当前值的操作。例如,采取以下方法:

public interface WordManagerMXBean {
     public void addWord(String word);
     public WordsObject getWords();
     public void removeWord(String word);
}
WordsObject是一个自定义的、可序列化的类,用于检索有关服务器状态的数据。然后我还有一个WordManager类,它实现了上述接口。然后,我创建一个JMX代理来管理我的资源:

MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName wordManagerName = new ObjectName("com.example:type=WordManager");
mbs.registerMBean(wordManager, wordManagerName);
我已经创建了一个调用这些方法的客户机,它可以按预期工作。但是,我想通过添加用户定义的异常来扩展当前配置,这些异常可以发送回我的客户机。所以我想把我的界面改成这样:

public interface WordManagerMXBean {
     public void addWord(String word) throws WordAlreadyExistsException;
     public WordsObject getWords();
     public void removeWord(String word);
}
public class WordAlreadyExistsException extends Exception implements Serializable {

private static final long serialVersionUID = -9095552123119275304L;

public WordAlreadyExistsException() {
    super();
    }
}
java.rmi.UnmarshalException: Error unmarshaling return; nested exception is: 
java.lang.ClassNotFoundException: com.example.WordAlreadyExistsException
我的WordReadyExistsException如下所示:

public interface WordManagerMXBean {
     public void addWord(String word) throws WordAlreadyExistsException;
     public WordsObject getWords();
     public void removeWord(String word);
}
public class WordAlreadyExistsException extends Exception implements Serializable {

private static final long serialVersionUID = -9095552123119275304L;

public WordAlreadyExistsException() {
    super();
    }
}
java.rmi.UnmarshalException: Error unmarshaling return; nested exception is: 
java.lang.ClassNotFoundException: com.example.WordAlreadyExistsException
当我在客户端中调用addWord()方法时,如果该词已经存在,我希望返回一个WordAlreadyExistsException。但是,当我执行此操作时,会出现如下错误:

public interface WordManagerMXBean {
     public void addWord(String word) throws WordAlreadyExistsException;
     public WordsObject getWords();
     public void removeWord(String word);
}
public class WordAlreadyExistsException extends Exception implements Serializable {

private static final long serialVersionUID = -9095552123119275304L;

public WordAlreadyExistsException() {
    super();
    }
}
java.rmi.UnmarshalException: Error unmarshaling return; nested exception is: 
java.lang.ClassNotFoundException: com.example.WordAlreadyExistsException
WordAlreadyExistsException、WordsObject和WordManagerMXBean接口都位于一个jar文件中,可供客户端和服务器使用。如果调用getWords()方法,客户端处理WordsObject不会有任何困难。但是,如果抛出了用户定义的异常(如上面的异常),则客户端会给出上面显示的错误。是否可以将JMX配置为在客户机中正确处理此异常

经过一些搜索,我注意到有一个MBeanException类用于包装异常。我不确定这个包装是由代理自动执行的,还是应该由我自己进行包装。我尝试了这两种方法,但在任何一种情况下,我都会在客户端上得到相同的错误

我也尝试过检查和未检查的异常,同样的错误再次发生

解决这个问题的一个方法是,在所有标准java异常都工作时,简单地将错误字符串传回一个通用错误中。但是我更愿意返回实际的异常以供客户机处理

是否可以在JMX中处理用户定义的异常?如果有的话,有什么办法吗

编辑:包括完整堆栈跟踪

java.lang.reflect.UndeclaredThrowableException
at $Proxy4.addWord(Unknown Source)
at com.example.TestClient.addWord(TestClient.java:76)
at com.example.TestClient.execute(TestClient.java:56)
at java.lang.Thread.run(Thread.java:722
Caused by: java.rmi.UnmarshalException: Error unmarshaling return; nested exception is: 
java.lang.ClassNotFoundException: com.example.WordAlreadyExistsException
at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:245)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:160)
at com.sun.jmx.remote.internal.PRef.invoke(Unknown Source)
at javax.management.remote.rmi.RMIConnectionImpl_Stub.invoke(Unknown Source)
at javax.management.remote.rmi.RMIConnector$RemoteMBeanServerConnection.invoke(RMIConnector.java:1017)
at  javax.management.MBeanServerInvocationHandler.invoke(MBeanServerInvocationHandler.java:305)
... 6 more
Caused by: java.lang.ClassNotFoundException: com.example.WordAlreadyExistsException
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at sun.rmi.server.LoaderHandler.loadClass(LoaderHandler.java:453)
at sun.rmi.server.LoaderHandler.loadClass(LoaderHandler.java:184)
at java.rmi.server.RMIClassLoader$2.loadClass(RMIClassLoader.java:637)
at java.rmi.server.RMIClassLoader.loadClass(RMIClassLoader.java:264)
at sun.rmi.server.MarshalInputStream.resolveClass(MarshalInputStream.java:216)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1593)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1514)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1750)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1964)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1888)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:369)
at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:243)
... 11 more

您的异常必须从扩展

    javax.management.JMException


如果它是RuntimeException。

而不是扩展RuntimeMBeanException,只需将RuntimeException作为RuntimeMBeanException的构造函数参数传递并抛出该异常即可。确保类路径中存在jar文件


如果jar文件存在于类路径中,扩展RuntimeMBeanException也可能起作用,但我没有测试可能发生的情况是,自定义异常被序列化,然后反序列化回应用程序服务器中,但由于缺少更好的词“classloader namespace”,扩展RuntimeMBeanException也可能起作用


尝试将包含自定义异常类的jar(c)与AppServer正在使用的jmxjar放在一起。确保从旧位置删除旧jar(我假设它位于WEB-INF/lib中的某个位置)。

虽然不建议抛出自定义异常,但肯定可以抛出自定义异常。从:

建议从 java SE上java.*和javax.*包中定义的标准集 如果MBean抛出非标准异常,那么 没有该异常类可能会看到另一个异常 例如ClassNotFoundException


因此,我会投入一些钱,让你的客户机根本没有加载
WordReadyExistsException
类。你可以检查这个相当简单的问题-在客户机中编写一个抛出此异常的方法,调用它,看看会发生什么。如果一切正常(确定=抛出了自定义异常,没有
ClassNotFoundException
)然后确保您的客户端和服务器具有包含
wordreadyexistexception
的jar版本。即使是最轻微的不匹配(例如,在包名中)可能是您的问题的根源。

我试图重现该问题,但对我来说效果很好;-(.请参阅下面的异常输出。我还打赌,这确实是客户端的类加载问题。您是否可以发布(精简)版的客户端jar(可能还有源代码)


你确定客户端类加载器中存在该类?你没有使用旧jar或其他东西运行?是的,我确定。我通过修改WordsObject类以包含一个额外字段、重建jar并用新字段替换现有jar文件来确认这一点。当我再次运行客户端时,我可以在WordsObject中获得新字段,但是我仍然得到了与异常相同的错误。您是否目视检查了jar的内容以确认该类在那里并且在正确的包中?我已经编辑了原始帖子以包含完整的堆栈跟踪。摘自Java管理扩展(JMX)规范中,MBeanException还包装了由用户定义并由MBean方法引发的实际异常可以包装并传递给mxbean客户端。有人知道这种情况吗?我已经尝试扩展MBeanException和RuntimeMBeanException。这些扩展了javax.management.JMException和javax.management.JMRuntimeException。我这样做时也会发生同样的错误。你做成功了吗?我没有得到异常类。我强烈怀疑它的类路径或您的Jar没有该类。@user1802492我的回答是为了澄清JMX实现必须抛出JMException或JMRuntimeException。它可以通过扩展或包装来实现。@Daniel-您可以尝试将接口更改为MXBean并抛出异常吗?如果是能拿到exc吗