【问题标题】:How can I call a method in an object from outside the JVM?如何从 JVM 外部调用对象中的方法?
【发布时间】:2010-09-26 23:54:58
【问题描述】:

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

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

我的实现考虑很典型

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

有没有“正确的方法”?如果不是,我有哪些选择,每种选择的优缺点是什么?

(人们实际做过并且可以提供真实反馈的东西会很棒!)

【问题讨论】:

    标签: java jvm communication


    【解决方案1】:

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

    • 非常容易实现
    • 非常容易从其他 JVM 调用
    • 支持远程机器
    • jconsole 允许您手动测试 MBean 而无需编写客户端

    缺点:

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

    【讨论】:

    • 谢谢,我心目中的调用者不是另一个 JVM,而是我认为的好答案
    【解决方案2】:

    JNI(Java 本地接口)允许从 C 或 C++ 访问 java 代码。

    【讨论】:

    • 我的班级在一个正在运行的 JVM 中;我想从外部调用类的方法。我认为 JNI 是一种使本机代码可以从 Java 类中使用的方法,所以我认为这不是我正在寻找的......
    • 啊?我以为是相反的。 IE。 Java 程序必须启动通信/实例化本机代码。
    • 发帖说得对,你可以启动一个JVM并从native代码调用Java类:java.sun.com/developer/onlineTraining/Programming/JDCBook/…
    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

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

        选项 3 IMO 是执行此操作的最“Java”方式,并且是最复杂/最容易出错的。 选项 2 丑陋但简单 选项 1 比较简单(java 部分),否则没问题。

        【讨论】:

          【解决方案6】:

          为了便于使用,我会使用Spring Remoting。如果你已经在你的项目中使用 Spring,那是没有道理的。如果你不是......好吧,无论如何你应该看看。

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

          【讨论】:

            【解决方案7】:

            您想要的是 Java 原生接口 (JNI),尽管它可能会带来一些困难。没有其他同等技术可以如此容易实施。

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

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

            【讨论】:

              【解决方案8】:

              好的。现在我知道客户端不是 Java,这是另一个尝试。由于您想要进程外访问和可能的远程机器访问,我认为 JNI 不是您想要的,因为这完全是进程内的(而且很麻烦)。以下是一些其他选项:

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

              XML-RPC :这在当今已经不那么时髦了,但它简单而有效。有Java libraries 以及大多数其他语言的库。

              CORBA:如上所述,CORBA 是一种选择,但它相当复杂,而且越来越难找到专家。

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

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

              【讨论】:

              • 如果能对此进行更新就好了,它在 java 17 或 11 中是否仍然相同?还有 MBean 和 jmx ?
              【解决方案9】:

              如果其他进程将在同一台计算机上并且操作系统是否符合 POSIX(不是 Windows),则要考虑的另一种替代方法是命名管道。

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

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

              【讨论】:

                【解决方案10】:

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

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

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

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

                【讨论】:

                  【解决方案11】:

                  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

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2019-10-22
                    • 1970-01-01
                    • 1970-01-01
                    • 2015-08-13
                    • 2016-02-11
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多