暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Java调用外部程序——Java基础

EffectiveCoding 2018-07-16
896

     我要做的是一个脚本的管理及控制系统,然后脚本之间存在依赖关系,首先需要一个任务调度模块,完成job(脚本集)Task(脚本)的关系控制及正确顺序执行,然后一个控制信息的管理系统,一个驱动脚本执行的模块,大概像是下面的一种结构。

    这两篇文章描述的是脚本驱动模块,首先我们需要明确要完成的功能。

    启动:可以通过传递shell命令的形式驱动脚本的执行

    查看:可以通过传递shell命令的形式查看当前shell脚本的进程状态

   终止:强制传递kill该子进程或通过调用process的函数终止外部的shell进程

    Java 操作外部程序的方式有这么几种:Runtime、Process(依赖Runtime)、ProcessBuilder


Runtime(使用方式):

1、exec方法接收一个命令然后执行,通过该方法可以执行和cmd中用法一样命令。比如,Runtime.getRuntime().exec(“ls”),就和cmd中执行ls效果一样了。

2、freeMemory()可以查看当前虚拟机内存中空闲内存还有多少。

3、totalMemory()可以查看当前虚拟机使用的总内存大小。

4、maxMemory()可以查看JVM的最终可以使用的最大内存是多少。

5、availableProcessors()可以查看本机有多少处理器,即本机处理器是多少核。

6、exit(int)方法可以退出当前Java程序的运行,System.exit(int)方法就是调用了Runtime.exit(int)方法来退出运行的。


process(依赖于Runtime):

1、waitFor()是让当前主进程等待这个process指向的子进程执行完成。

2、exitValue()可以查看process指向的子进程执行完的退出值,0代表是正常运行结束。

3、destroy()和destroyForcibly()可以终止process子进程的运行,后者是强制终止,前者与平台终止进程的具体实现有关。


ProcessBuilder

1、创建ProcessBuilder不需要通过Runtime,而Runtime.getRimtime().exec(string)正是调用了ProcessBuilder的构造方法来创建子进程并执行的。

传参问题:当传递的参数字符串中包含空格时,会把参数截断,默认为参数只到空格处。

解决:将shell 命令或脚本 和参数 放在一个 数组中,然后将数组传入exec()方法中。

2、ProcessBuilder的构造方法接收一个命令参数的数组形式,其中,第一个元素代表要执行的系统命令,后面的元素代表要传给该命令的参数。

3、调用.start()方法运行之后,就可以获得该子进程的Process引用了,然后就可以调用Process的方法进行处理。


ProcessBuilder核心总结:

核心使用:

start():启动进程

waitFor();等待命令结束后返回

其他:

command() 返回此进程生成器的操作系统程序和参数。 

command(List<String> command)设置此进程生成器的操作系统程序和参数。 

command(String... command) 设置此进程生成器的操作系统程序和参数。 

directory()返回此进程生成器的工作目录。 

directory(File directory) 设置此进程生成器的工作目录。 

environment() 返回此进程生成器环境的字符串映射视图。 可以获取到系统默认的环境变量

redirectErrorStream()通知进程生成器是否合并标准错误和标准输出。 

redirectErrorStream(boolean redirectErrorStream)设置此进程生成器的 redirectErrorStream 属性。 


Process:

getInputStream() :标准输出

getErrorStream() :标准错误输出

info:进程当前信息

pid:当前进程号


权限问题:存在脚本无权限执行的问题

解决ProcessBuilder builder = new ProcessBuilder("/bin/chmod", "755",scriptPath);

注意:

process创建的子进程没有自己的控制台或终端,其所有的io操作都是通过(输入流、输出流、错误流)重定向到父进程中

更加合适的选择:

Java ProcessBuilder,但需要注意Error信息的收集


    以上几种方式已经完成了对应的Java调用本地的外部程序(此处是shell),但很多时候我们需要完成对于非本地机器的shell调用,这时候我们需要使用Java的远程连接工具,比如说Ganymed SSH-2 for Java。

    Ganymed SSH-2 for Java是用纯Java实现SSH-2协议的一个包。可以利用它直接在Java程序中连接SSH服务器。Ganymed SSH-2支持SSH对话(远程命令执行和shell访问),本地和远程端口转发,本地数据流转发,X11转发和SCP。这些都没有依赖任何JCE provider,而且所有这些都包含加密的功能。 

    看到这里我们已经能够驱动外部程序执行了,剩下的是外部程序执行(进程)的管理策略。

    假如使用ProcessBuilder进行构建基础模块

    首先要完成对于进程的驱动执行,我们可以获得对应进程的相关信息(pid、执行时间、系统环境等)。

    是时候看一眼代码了

List<String> cmd=Arrays.asList("/bin/bash","-c","./test.sh");

String workDir="/Users/zouzhiquan/workspace/vim";

ProcessBuilder processBuilder=new ProcessBuilder(cmd);

processBuilder.directory(new File(workDir));

processBuilder.environment();

//到这一步,已经完成了相关的准备工作

processBuilder.redirectError();

然后我们需要重定向Error,方便补货

Process process=processBuilder.start();

//启动对应的外部程序,并获取对应的process,这里可以简单理解为获取你正在执行的进程对象

process.info();

process.pid();

process.getInputStream();

process.getErrorStream();

//可以使用以上方法完成对于进程信息的采集。


    完成启动之后,剩下的便是进程的终止、进程的查看、重试逻辑(Error的处理策略)

    这时候仅需要根据已有的信息,对于进程进行操作即可,拿到pid一切就都好说了,但是对应策略逻辑要注意上篇发的操作系统基础,注意进程的操作逻辑。

    如果是远程机器使用Ganymed SSH-2 for Java 完成对应的远程连接、命令传递即可。


文章转载自EffectiveCoding,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论