Java:命令执行被卡住



我有一个安装程序。安装程序调用方法doSetup()来执行以下操作:

  1. 使用setx命令设置CATALINA_HOME变量(将变量永久存储在系统变量中(
  2. 使用set命令设置CATALINA_HOME变量(将CATALINA_HOME用于当前cmd会话(
  3. 将tomcat作为服务安装
  4. 更新服务名称

以下是doSetup()的实现

private void doSetup() {
String installPath = InstallData.getInstance().getInstallPath();
String setConfigCommon = installPath + "\EmbeddedTomcat\bin\tomcat8 //US//Tomcat8";
String catalinaHome = installPath + "\EmbeddedTomcat";
catalinaHome = """ + catalinaHome + """;
String setxCatalinaHome = "setx CATALINA_HOME " + catalinaHome + " /m";
String setCatalinaHome = "cmd.exe /c set CATALINA_HOME=" + catalinaHome;
String installService = installPath+"\EmbeddedTomcat\bin\service.bat install";
String setName = " --DisplayName="MyService"";
if(installPath.endsWith("\")) {
installPath = installPath.substring(0, installPath.length()-1);
}
Exception exception =  null;
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
try {
log.info("SETX : CATALINA_HOME");
InstallHelper.executeCommand(setxCatalinaHome);
log.info("SETX : DONE");
Thread.sleep(500);
}
catch(Exception e) {
e.printStackTrace(pw);
exception = e;
log.info(e.getMessage());
}
try {
log.info("SET : CATALINA_HOME");
InstallHelper.executeCommand(setCatalinaHome);
log.info("SET : DONE");
Thread.sleep(500);
}
catch(Exception e) {
e.printStackTrace(pw);
exception = e;
log.error(e.getMessage());
}
try {
log.info("INSTALL : Service");
InstallHelper.executeCommand(installService);
log.info("INSTALL : DONE");
Thread.sleep(500);
}
catch(Exception e) {
e.printStackTrace(pw);
exception = e;
log.error(e.getMessage());
}
try {
log.info("UPDATE: Service name");
InstallHelper.executeCommand(setConfigCommon + setName);
log.info("UPDATE: DONE");
Thread.sleep(500);
}
catch(Exception e) {
e.printStackTrace(pw);
exception = e;
log.error(e.getMessage());
}
}

下面是executeCommand()的实现

public static String executeCommand(String commandName) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
try {
StringBuffer result = new StringBuffer();
String line;
Process p = Runtime.getRuntime().exec(commandName);
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = input.readLine()) != null) {
result.append(line);
result.append("n");
}
input.close();
return result.toString();
}
catch (Exception err) {
err.printStackTrace(pw);
log.error(sw.toString());
}
return null;
}

当我查看日志时,我发现(上面提到的4个步骤中的(第3步正在执行,然后在更新服务时被卡住。这就是日志文件的样子:

[18-10-22 15:38:22] INFO  panels.InstallationSurvey - Check log is writable, SUCCESS
[18-10-22 15:38:29] DEBUG panels.InstallationSurvey - Windows PROCESSOR_ARCHITECTURE: AMD64
[18-10-22 15:38:29] INFO  panels.InstallationSurvey - 64-Bit Windows found!
[18-10-22 15:38:29] INFO  panels.InstallationSurvey - <B>COMPLETE</B>
[18-10-22 15:38:30] INFO  panels.PreInstallPanel - <b>COMPLETE</b>
[18-10-22 15:38:38] INFO  panels.PortCheckPanel - Port Test SUCCESS
[18-10-22 15:39:25] INFO  panels.WindowsServicePanel - SETX : CATALINA_HOME
[18-10-22 15:39:25] INFO  panels.WindowsServicePanel - SETX : DONE
[18-10-22 15:39:25] INFO  panels.WindowsServicePanel - SET : CATALINA_HOME
[18-10-22 15:39:26] INFO  panels.WindowsServicePanel - SET : DONE
[18-10-22 15:39:26] INFO  panels.WindowsServicePanel - INSTALL : Service
[18-10-22 15:39:26] INFO  panels.WindowsServicePanel - INSTALL : DONE
[18-10-22 15:39:27] INFO  panels.WindowsServicePanel - UPDATE: Service name

有趣的事实:我已经运行了很多次安装程序。有时它没有卡住,有时它会像描述的那样卡住。

我需要添加/删除任何代码来消除这种奇怪的行为吗?或者有什么建议吗?

有时它不会卡住

可能是因为您没有等待命令终止。参见java.lang.Process类中的方法waitFor。然后,您还可以移除对〔static〕方法sleep(类Thread(的调用。

Runtime不是Windows命令提示符。您应该使用类java.lang.ProcessBuilder

您的代码应该类似于以下内容:
(请注意,以下内容仅为摘录,以说明您需要进行哪些更改。(

方法doSetup

private void doSetup() {
String installPath = InstallData.getInstance().getInstallPath();
String catalinaHome = installPath + "\EmbeddedTomcat";
catalinaHome = """ + catalinaHome + """;
List<String> setxCatalinaHome = List.of("setx", "CATALINA_HOME", catalinaHome, "/m");
InstallHelper.executeCommand(setxCatalinaHome);
}

方法executeCommand

public static String executeCommand(List<String> commandName) {
StringBuffer result = new StringBuffer();
try {
String line;
ProcessBuilder pb = new ProcessBuilder(commandName);
Process p = pb.start();
BufferedReader input = p.inputReader();
while ((line = input.readLine()) != null) {
result.append(line);
result.append("n");
}
int status = p.waitFor();
if (status != 0) {
// Command failed. What to do?
}
return result.toString();
}
catch (Exception err) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
err.printStackTrace(pw);
log.error(sw.toString());
}
return null;
}

执行的命令可能会失败。你需要处理这种情况。此外,在JDK 17中添加了方法inputReader。如果您使用的是较低的JDK版本,则可以选择getInputStream(您当前正在使用(。顺便说一句,关闭BufferedReader也会尝试关闭封装的InputStream,但您没有创建那个InputStream,因此不应该关闭它,所以我建议删除关闭BufferedReader的代码。

还要注意,在执行命令之前,您可能需要显式设置工作目录。请参阅类ProcessBuilder中的方法目录。

相关内容

  • 没有找到相关文章

最新更新