【问题标题】:Java program that calls external program behaving asynchronously?调用异步行为的外部程序的Java程序?
【发布时间】:2013-11-07 11:53:58
【问题描述】:

全部,

我最初有一个名为 SQLLoader(Oracles 数据上传工具)的 shell 脚本。

问题在于 SQLLoader 将纯文本密码作为输入,因此我决定构建一个 Java 应用程序以在内部调用 SQLLoader,并将解密的密码传递给命令字符串。

例如

sqlldr user/pass@DBServer control=../sqlloader.ctl log=sqlloader.log data=mydata.csv

所以使用我的 java 包装器,它在我的 shell 脚本中变成了这个

java -jar sqlloader.jar sqlloader.ctl mydata.csv

但是,当 SQLLoader 抱怨没有要加载的文件时,出现了一个新问题。经过一番摸索后,我发现我的 shell 脚本中的后续命令似乎正在执行,而我的 java 应用程序仍在运行。因此它的行为是异步的。

下一个命令是在 sqlloader 有机会使用它之前移动输入文件。所以我在 20 秒内输入了一个 sleep 命令,让我的 java 应用程序有时间运行。

java -jar sqlloader.jar sqlloader.ctl mydata.csv
echo $?
sleep 20
if [ $? -ne 0 ]
    then
        echo "SQLLoader failed during execution, please check the log : " 
        mv mydata.csv

else
    echo "SQLLoader successfully processed file : "
    mv mydata.csv
fi

有谁知道为什么 unix 会这样,Java 是否将我的 SQLLoader 作为不同的用户/线程执行?

这是我的java代码:

    Runtime Rt;
Process Prc;
    Prc = Rt.exec("sqlldr user/decryptedpass@DBServer control=../sqlloader.ctl log=sqlloader.log data=mydata.csv);
system.exit(0);

我检查了运行时类是否有任何关于它是异步的但找不到任何东西

http://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html

有什么理论或建议吗?

谢谢

【问题讨论】:

  • 执行后你在代码中做了什么?
  • system.exit(0);是我在 java 程序中的最后一行
  • 这可能是题外话,但是......加密密码的意图是什么?您真的像示例代码一样在 Java String 中硬编码密码吗?如果是这样,黑客可以解压缩jar 文件并查看.class 文件,密码将只是明文。 JavaRuntime.exec 底层处理复杂,应该有更简单的方法。

标签: java shell asynchronous sql-loader


【解决方案1】:

是的。如果您再次查看 Runtime.exec,它确实指定它将在指定的环境中启动一个新进程(例如,独立于当前的“环境”或您将其异步放置)。您应该使用ProcessBuilder 创建一个Process,然后在调用 System.exit 之前等待该进程完成 - 这当然不是强制性的。像这样的

public static void main(String[] args) {
    // String command = "/usr/bin/sleep 5";
    List<String> command = new ArrayList<String>();
    command.add("c:/cygwin/bin/sleep");
    command.add("5");
    ProcessBuilder pb = new ProcessBuilder(command);
    BufferedReader is = null;
    try {
        System.out.println("Starting command " + command);
        Process p = pb.start();

        int ret = p.waitFor();
        is = new BufferedReader(new InputStreamReader(p.getInputStream()));
        String line;
        while ((line = is.readLine()) != null) {
            System.out.println(line);
        }
        if (ret == 0) {
            System.out.println("Command has completed.");
            System.exit(ret);
        } else {
            System.out.println("Command completed with return code " + ret);
            System.exit(ret);
        }
    } catch (Exception e) {
        System.out.println("Caught Exception " + e.getMessage()
                + " running command " + command);
        e.printStackTrace();
    } finally {
        if (is != null) {
            try {
                is.close();
            } catch (IOException e) {
            }
        }
    }
    System.out.println("COMMAND FAILED");
    System.exit(1);
}

【讨论】:

  • 这会将进程的输出获取到控制台吗?
【解决方案2】:

您需要等待进程完成,您还应该从您正在启动的进程中读取所有输出(stdout stderr)。

如果您在 exec() 之后调用 exit(),Java 将执行此操作 - 立即退出。

这是一篇解释 Runtime.exec 陷阱的文章:http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=4(也请考虑其他页面)。

【讨论】:

  • 只是添加一些颜色,请致电Prc.waitFor()。摆脱睡眠,这是等待发生的时间错误。
猜你喜欢
  • 2014-09-12
  • 2016-05-29
  • 1970-01-01
  • 1970-01-01
  • 2019-08-09
  • 2015-06-11
  • 2020-07-28
  • 1970-01-01
  • 2011-09-14
相关资源
最近更新 更多