如何从JVM外部调用对象中的方法?

我有一个非常简单的Java类,它使用输入validation有效地装饰Map,使用明显的void set()和String get()方法。

我希望能够有效地调用这些方法并处理来自JVM外部的返回值和exception,但仍然在同一台机器上更新:我想到的调用者不是另一个JVM; 谢谢@Dave Ray

我的实施考虑是典型的

  • 性能
  • 易于实施和维护(简单?)
  • 可靠性
  • 灵活性(即我可以从远程机器呼叫等)

有没有“正确的方法?” 如果没有,我的选择是什么,每个人的利弊是什么?

(事实上​​,人们已经完成并可以提供真实的反馈意见!)

好。 这是另一个尝试,因为我知道客户端不是Java。 由于您需要进程外访问以及可能的远程机器访问,因此我认为JNI不是您想要的,因为这是严格的进程(并且总是麻烦)。 以下是一些其他选项:

原始套接字 :只需在Java中设置一个侦听器套接字并接受连接。 当您获得连接时,请阅读请求并发回响应。 几乎每种语言都可以使用套接字,因此这是一个非常通用的解决方案。 但是,您必须定义自己的编组方案,解析等。

XML-RPC :现在这不像时髦,但它简单而有效。 大多数其他语言都有Java库和库。

CORBA :如上所述,CORBA是一种选择,但它非常复杂,专家越来越难以接受。

Web服务器 :在您的应用程序中设置嵌入式Web服务器并处理请求。 我听说过关于Jetty的好东西,或者你可以使用Java提供的那个。 我已经成功地使用后者通过用Java编写的模拟将KML文件服务到Google Earth。 大多数其他语言都有用于发出HTTP请求的库。 如何编码数据(XML,文本等)取决于您。

Web服务 :我认为这会更复杂,但您可以使用JAX-WS将对象公开为Web服务。 NetBeans有很好的工具来构建Web服务,但这可能有点过分。

您是从另一个基于JVM的系统调用,还是客户端语言是任意的? 如果您从另一个JVM调用,最简单的方法之一是通过JMX将对象公开为MBean。 这里显示了规范的Hello World MBean。 专业人士是:

  • 真的很容易实现
  • 从其他JVM调用真的很容易
  • 支持远程机器
  • jconsole允许您在不编写客户端的情况下手动测试MBean

缺点:

  • 客户端必须在JVM上(我认为)
  • 对于更复杂的数据结构和交互并不好。 例如,我不认为MBean可以返回对另一个MBean的引用。 它将序列化并返回一份副本。

由于您的呼叫者不是Java应用程序,并且您已经预见到网络呼叫者,因此RMI-IIOP(CORBA)可能是一种选择。 虽然它绝对不容易实现,但它具有成为广泛认可的标准的优势。

由于您的调用者不是基于JVM的,因此这是与JVM进行进程间通信的问题。 我想到的选择是:

  1. 通过套接字进行通信:使您的JVM监听传入连接和呼叫者发送命令
  2. 使用共享文件进行通信(调用者写入文件,JVM轮询和更新)
  3. 使用JNI,在调用者进程内启动JVM,然后使用RMI / MBean与第一个(“服务器”)JVM进行通信。 调用者可以使用JNI访问结果

选项3 IMO是执行此操作的最“Java”方式,并且是最复杂/容易出错的方式。 选项2很丑但很简单选项1适度容易(java部分),否则就可以了。

为了便于使用,我会使用Spring Remoting 。 如果你已经在项目中使用Spring,那就没问题了。 如果你不……那么你应该看看。

Spring提供了一个抽象,允许您轻松切换远程协议。 它支持最广泛部署的协议(SOAP,Hessian,Burlap,RMI,……)。 如果您使用非Java代码调用, Hessian支持许多其他语言,已知比SOAP更高效且比CORBA更容易。

JNI(Java Native Interface)允许从C或C ++访问Java代码。

我有一个Inno安装脚本(安装Java程序),它调用一些Java方法来执行某些操作或检查某些条件。
我(实际上是我的前任)只是在每次调用时实例化java.exe。 显然,这是昂贵的,虽然在我的情况下并不重要(我认为Windows缓存开始了)。

另一种方法是使用一些语言间通信/消息传递,Java程序充当服务器。 Corba浮现在脑海中,因为它与语言无关。 但也许有点沉重。 你可以使用套接字。 RPC也是另一个流行语,但我在该领域没有多少经验。

你想要的是Java Native Interface(JNI),尽管它可能存在困难。 没有其他同等技术易于实施。

正如前面答案的注释中所提到的,JNI针对从Java调用本机代码进行了优化,但它也可以用于反向工作。 在您的本机代码中,您需要实现JNI入口点 – 类似于SetMapPointer() – 然后在构建Map之后从Java代码调用该函数。 SetMapPointer()的实现应该保存Java对象指针在某处可访问,然后本机代码可以根据需要调用它上面的Java方法。

您需要确保以正确的顺序发生这种情况(即本机代码在构建之前不会尝试访问Map并传递给本机代码),但这不应该是一个特别难的问题。

考虑另一个进程是否在同一台机器上并且操作系统符合POSIX(不是Windows)的另一种选择是命名管道。

当Java应用程序从管道读取时,外部进程将操作(作为字符串或其他一致的字节编码)写入命名管道,解析传入的操作并针对您的对象执行它们。

这与您用于套接字连接的策略相同,而不是您要从附加到命名管道的FileInputStream读取的SocketInputStream。

CORBA的替代方案是ICE ,除非许可证是一个问题(它是GPL,但您也可以购买商业许可证)。

它具有CORBA的所有优点,但供应商ZeroC提供了许多不同语言的绑定。 CORBA供应商往往只提供一个或两个语言绑定,然后您开始发现兼容性问题。

文档也很棒。 我不会说它特别容易拿起,但可能比CORBA更容易。

否则,我认为没有提到的另一个选择是思科开发的新中间件/ RPC框架,现在捐赠给Apache,称为Etch 。 它仍然很新,而且文档很少。

Beanshell是一个类似shell的java解释器,可以通过网络套接字公开。 基本上你从java做到这一点:

i = new bsh.Interpreter(); i.set( "myapp", this ); // Provide a reference to your app i.eval("server(7000)"); 

然后你从其他地方做到这一点:

 telnet localhost 7001 myapp.someMethod(); 

这个小实用程序比JNI或RMI更容易进行远程java调用。

有关更多信息,请访问: http : //www.beanshell.org/manual/remotemode.html