【问题标题】:Start a java program with an object model as parameter以对象模型作为参数启动 java 程序
【发布时间】:2009-07-19 18:44:11
【问题描述】:

服务器侦听端口,等待来自客户端的传入请求(客户端实际上是一个 ejb)。这些请求将完整的对象模型作为参数传递(例如,员工列表、每个员工的任务列表等)。

现在服务器必须在同一台机器上在新的 JVM 实例中启动另一个 java 程序,并使用这个对象模型作为参数。

这个其他 java 程序应该是一个独立的 java 程序,但我不能将对象模型作为参数传递给 main 方法 (void main(String[] args))。

那该怎么办?我正在寻找一个“简单”的解决方案,例如最好没有用于持久性的数据库或文件。 独立程序确实是 cpu 密集型的,不能由应用服务器托管。

谢谢。

【问题讨论】:

    标签: java remoting


    【解决方案1】:

    运行应用程序并捕获其输入/输出流,然后通过它流式传输序列化的对象模型。新应用程序应该反序列化来自 System.in 的输入。

    概念示例(我只是想确保我的示例有效,抱歉耽搁了):

    package tests;
    
    import java.io.File;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    
    public class AppFirst {
        public static void main(String[] args) throws Exception {
            ProcessBuilder pb = new ProcessBuilder("java", "-cp", 
                "./bin", "tests.AppSecond");
            pb.directory(new File("."));
            pb.redirectErrorStream(true);
            Process proc = pb.start();
    
            ObjectOutputStream out = new ObjectOutputStream(
                proc.getOutputStream());
            ObjectInputStream oin = null;
    
            for (int i = 0; i < 1000; i++) {
                out.writeObject("Hello world " + i);
                out.flush();
                if (oin == null) {
                    oin = new ObjectInputStream(proc.getInputStream());
                }
                String s = (String)oin.readObject();
                System.out.println(s);
            }
            out.writeObject("Stop");
            out.flush();
    
            proc.waitFor();
        }
    }
    

    package tests;
    
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    
    public class AppSecond {
        public static void main(String[] args) throws Exception {
            ObjectInputStream oin = null;
            ObjectOutputStream out = new ObjectOutputStream(System.out);
            while (true) {
                if (oin == null) {
                    oin = new ObjectInputStream(System.in);
                }
                String s = (String)oin.readObject();
                if ("Stop".equals(s)) {
                    break;
                }
                out.writeObject("Received: " + s);
                out.flush();
            }
        }
    }
    

    编辑:添加了循环版本。请注意,OOS 需要一个技巧,因为它会立即开始读取传入的流(并阻止您的应用程序如果您在错误的步骤中执行此操作 - 它应该在第一个 AFTER 之后包装对象被发送到子进程)。

    【讨论】:

    • 您的解决方案与“乔治四世”建议的解决方案相比如何?如果请求很多,这个解决方案也能执行吗?
    • 坦率地说,我从未尝试将多个对象写入 OOS。您可以将两个示例应用程序中的请求和响应对包装到一个 for 循环中并执行 1000 次。我现在会检查并返回。
    • @akarnokdthis 对我不起作用。你能帮我解决这个问题吗?我正在从大量数据中生成碧玉报告。但它永远在等待。最后,应用程序挂起,最后不得不终止进程。
    【解决方案2】:

    看看RMI。您的服务器可以启动新服务,该服务又将自身发布并导出到本地注册表。然后,您的新服务可以接收对象模型作为远程扩展方法的参数。应该非常简单,不需要文件访问或附加服务,并且不比任何其他答案更重要。

    【讨论】:

      【解决方案3】:

      您可以序列化对象并将其写入文件系统。然后,您可以在运行时读入该序列化对象。或者,您可以使用 JMS 将该对象作为字节流传输。

      More on serialization.

      More on JMS。我一直使用 ActiveMQ,一个 Apache 项目来满足我的 JMS 需求。它易于使用且高度可扩展。哦,是的,而且它是免费的。

      【讨论】:

      • - JMS 解决方案:它是否需要软件安装形式的任何开销? - 序列化:读取后真的会还原原始对象吗?有初学者的例子吗?
      • 查看编辑。我从未在 ActiveMQ 之外使用过 JMS,我建议这样做。序列化的对象被读回,就好像它们从未消失过一样。只有transient 变量丢失。但它们不应该是以后使用的必需品(这就是为什么它们被标记为transient)。
      • 你觉得kd304的解决方案怎么样?
      【解决方案4】:

      一种方法是原始 JVM 打开一个套接字进行侦听,新的 JVM 实例运行一个连接到该套接字并通过该套接字接收参数的程序(Java 的默认序列化可能就足够了)。这样您只需将套接字端口号作为参数传递给 main,不需要文件/数据库。同样的方法也可以用于在 JVM 之间传递其他命令。

      【讨论】:

      • - 原来的JVM怎么会知道新机器已经读取了参数,它可以检测到吗? - 每分钟有多少请求:我应该在端口号旁边传递一个唯一的 id 作为参数,以便传递正确的对象模型吗?
      • (1) 客户端在读取数据后向原始 JVM 发送一条消息可能会很好,因为它已经收到了所有数据,因为可能会有短暂的延迟(几毫秒) 在通过套接字发送数据的原始 JVM 和接收它的客户端之间。 (2) 为您启动的每个 JVM 设置不同的端口。这样端口号是唯一的,您将知道哪个 JVM 连接到它,因为您只将端口号告诉一个 JVM。
      【解决方案5】:

      无论哪种方式,您都不能传递内存中存在的对象模型。如果你想传递对象模型,你将不得不找到一种方法来将该模型编码和解码成你可以传递的东西。

      由于数据已经通过 EJB 发送,对象序列化是显而易见的选择,尽管 XML、JSON 等没有任何问题。

      您还需要将对象从您的服务器程序获取到新调用的 JVM。如果对象模型足够小,您可以将序列化对象作为命令行参数传递给 java 程序。您也可以按照 George IV 的建议将其写入文件系统,然后告诉您的新应用程序在哪里可以找到包含序列化数据的文件。您可以使用 JMS。网页服务。插座。

      但如果您的服务器应用程序已经基于 EJB,最简单的做法是让您的新应用程序作为 EJB 客户端在 EJB 层上调用,以请求您正在查找的数据。

      【讨论】:

      • 这可能是一个很好的解决方案。 1.) ejb 调用远程套接字,2.) 服务器启动独立 java 程序和 3.) 独立程序开始连接到 ejb 以获取它的模型。现在关于沟通:我必须在步骤 1. 和 2. 中传递哪些信息,以便步骤 3. 知道该做什么以及在哪里做?
      【解决方案6】:

      序列化方法很好。此外,您还需要根对象来携带对调用相关对象的一些引用。我过去做的是序列化一个完整的对象图,让根对象实现一些接口,如Runnable,然后在接收节点上将此根对象转换为Runnable,并在其上执行run()

      【讨论】:

      • “调用的相关对象”是什么意思?
      • 取决于您的功能所在的位置。如果它在序列化类的代码中,那么你不需要关心它。另一方面,如果图形的某些对象作为参数与服务器上的函数相关,即在序列化类之外,那么您可以只使用 Object[] 作为根对象并将内容传递给接受Object[].
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-03
      • 1970-01-01
      • 2016-12-05
      • 1970-01-01
      • 1970-01-01
      • 2012-05-29
      相关资源
      最近更新 更多