&引用;adb启动服务器";,Java、Gradle和ApacheCommonsExec:如何使其正确?

&引用;adb启动服务器";,Java、Gradle和ApacheCommonsExec:如何使其正确?,java,gradle,adb,apache-commons-exec,Java,Gradle,Adb,Apache Commons Exec,当我试图从Java内部作为外部进程运行android start server时,遇到了各种各样的问题。Java由Gradle调用。让我向您描述一下在各种情况下到底发生了什么: 环境 Windows 7 X64 爪哇7 commons-exec-1.1 梯度1.6 安卓API 17 IntelliJ IDEA 12.1.4社区版 假设 adb守护程序被终止,并将在调用adb启动服务器时启动 案例1 此代码: DefaultExecutor executor=new org.apache.co

当我试图从Java内部作为外部进程运行android start server时,遇到了各种各样的问题。Java由Gradle调用。让我向您描述一下在各种情况下到底发生了什么:

环境

  • Windows 7 X64
  • 爪哇7
  • commons-exec-1.1
  • 梯度1.6
  • 安卓API 17
  • IntelliJ IDEA 12.1.4社区版
假设
adb守护程序被终止,并将在调用
adb启动服务器时启动

案例1 此代码:

DefaultExecutor executor=new org.apache.commons.exec.DefaultExecutor();
executor.execute(org.apache.commons.exec.CommandLine.parse(“adb启动服务器”);
log.info(“Checkpoint!”);
从应用程序插件的Gradle
run
task运行时,将显示启动服务器输出,即:

* daemon not running. starting it now on port 5037 *
* daemon started successfully *
然后它将挂起,即“Checkpoint!”将永远不会被记录。手动终止
adb.exe
进程将导致代码继续执行

问题1 为什么这个电话会阻塞?当从终端运行
adb start server
命令时,几秒钟后控制返回到终端,那么为什么代码中不会发生这种情况呢

案例2 如果我直接使用Java运行时,就像这样:

Runtime.getRuntime().exec(新字符串[]{“adb”,“启动服务器”});
log.info(“Checkpoint!”);
系统出口(0);
如果像以前一样从Gradle调用,“检查点!”将被记录。但是,执行将挂起
系统。退出(0)
。手动终止adb.exe将再次使Gradle调用完成

在这种情况下,不会显示
adb启动服务器的输出

有趣的是,当我从IntelliJ IDEA运行应用程序而不是Gradle时,构建设置与Gradle类似,一切正常,应用程序正常完成

问题2 为什么Gradle挂起
系统。退出(0)
而IntelliJ不挂起?这与Gradle本身是一个在内部调用Java的进程,而在IntelliJ中,Java是在没有任何间接寻址的情况下立即调用这一事实有什么关系吗?为什么这很重要

问题3
最终,我希望能够在没有任何挂起的情况下从Gradle运行此程序。记录adb启动服务器的输出将是一个额外的好处。如果您能给我一些提示,我将不胜感激。

如果我回答了错误的问题,请原谅,但是如果我想从gradle启动一台服务器(我们为tomcat、sonicMQ、ApacheDS和EnterpriseDB这样做),我会从gradle Exec任务开始,如果它不合适,我只会尝试其他任务

task startADB(type: Exec) {
    commandLine 'adb', 'start-server'
}

不幸的是,我不能回答你关于各种代码挂起的任何问题,因为我一点线索也没有!我只知道如果我想从gradle启动服务器,我会这么做。事实上,我就是这样做的。另一个稍微复杂一点的选择是使用或类似的东西。您仍然可以从gradle启动和停止它,但您可以获得一些高级功能。

最终,我通过执行以下操作解决了问题:

  • 在我的程序中,为了调用
    adb启动服务器
    ,我不再使用
    org.apache.commons.exec.defaultexector.execute(“adb启动服务器”)
    或Java的
    Runtime.getRuntime().exec(“adb启动服务器”)

    相反,我使用
    java.lang.ProcessBuilder(“adb启动服务器”).inheritIO().start().waitFor()
    。注意,
    inheritaio()
    是在Java 7中添加的,它允许在线读取已启动的进程stdout等。
    EDIT与IntelliJ IDEA调用Gradle不同,直接从CLI调用Gradle时,Gradle中的
    Inheritario()
    无效。有关详细信息,请参阅。 按照描述实施
    StreamGobbler
    可能会解决问题

  • 在Gradle中,我再次使用
    ProcessBuilder
    重用
    run
    任务变量,而不是Gradle的
    run
    任务。看起来是这样的:

  • 至于这些奇怪的行为的原因,我没有任何明确的答案,所以我不做进一步的评论

    编辑2013年7月9日
    似乎指出问题2的答案是:在windows上,父进程在终止前等待子进程。不幸的是,由于问题1中所述的问题,这里提出的解决方案不起作用

    希望这有帮助,

    康拉德

    谢谢!事实上,我正在考虑从外部启动亚洲开发银行,以规避我面临的所有问题。目前我认为Gradle挂起是因为应用程序插件的“运行”任务存在流缓冲问题(我查看了源代码)。也许是因为同样的原因,commons exec挂起。我继续调查……tanuki包装器允许您将基本上任何东西作为服务安装(在windows和linux中),并且它可以在不挂起的情况下更好地启动。gradle Exec变成了一个简单的“净启动”或“/etc/init.d/foo start”。我检查:gradle的
    Exec
    任务也挂起
    System.exit(0)
    。但是,此命令工作正常:
    newprocessbuilder(“adb”,“启动服务器”).inheritIO().start()它不挂起在任何配置中,并显示输出。
    
    apply plugin: 'java'
    apply plugin: 'application'
    
    sourceCompatibility = '1.7'
    targetCompatibility = '1.7'
    
    // configuration-time of the original run task
    run { 
        main = com.example.MainClass; // without this, our custom run will try to run "null"
    }
    
    task myRun(dependsOn: build) {
    
            // execution-time of our custom run task.
            doFirst {
    
                ProcessBuilder pb = new ProcessBuilder(tasks['run'].commandLine);
                pb.directory(tasks['run'].workingDir);
    
                // works when the gradle command is executed from IntelliJ IDEA, has no effect when executed from standalone CLI interface.
                pb.inheritIO(); 
    
                Process proc = pb.start();
                proc.waitFor();
            }
        }