我有一个安装程序。安装程序调用方法doSetup()
来执行以下操作:
- 使用
setx
命令设置CATALINA_HOME变量(将变量永久存储在系统变量中( - 使用
set
命令设置CATALINA_HOME变量(将CATALINA_HOME用于当前cmd
会话( - 将tomcat作为服务安装
- 更新服务名称
以下是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
中的方法目录。