San*_*ors 3 java process selenium-chromedriver
我有一个进程(在 Windows 上名为chromedriver.exe),它是在我创建Selenium Chrome Driver的新实例时创建的。
所以我不会自己开始这个过程,但java.lang.Process如果可能的话,我想要一个代表该过程的实例。
我想创建这样的实例的原因是我想Process.waitFor()在我发出(如果在 Windows 上)a 之后调用等待直到进程实际终止Runtime.getRuntime().exec("taskkill /F /IM chromedriver.exe")。
我不能仅针对此特定需求引入对第三方库的新依赖。我可以使用 Apache Commons 中的任何东西。
所以问题是:有没有办法从我的代码中获取一个Process代表未从我的代码启动的正在运行的进程的实例?
我希望能够终止该进程的原因是像 JVM 崩溃这样的突然终止可能不会WebDriver.quit()终止该进程。因此,在创建导致进程启动的 ChromeDriver 实例之前,我想终止任何可能已经存在的此类进程。
我使用exec("taskkill...")在 Windowskillall上终止进程的原因(我在 Linux 上使用)是到目前为止我发现的唯一方法,但是如果有可能获得Process代表该进程的实例,我也会尝试使用Process.destroy(),以查看是否在提到的“子”其描述“杀死子进程”指的是这一进程。
简而言之,不是用 Java 吗?8,但可以使用 Java 9和java.lang.ProcessHandle.
ProcessJava 中的A并不是要对任意操作系统进程进行建模,它实际上是对 java 进程的子进程进行建模,因此您不能附加到另一个正在运行的进程,并期望获得 a 的所有功能Process:
Process 类提供了执行进程输入、执行输出到进程、等待进程完成、检查进程退出状态以及销毁(杀死)进程的方法。
如您所见,输入和输出要求您的 java 进程拥有另一个进程的 stdin/stdout/stderr 的句柄,这仅对子进程有意义。该文档还到处提到“子进程”,因此暗示它是一个子进程。
在 Java 9 中,文档明确以:
Process 提供对由
ProcessBuilder.start和启动的本机进程的控制Runtime.exec。
但是 Java 9 也带来了ProcessHandle,这正是您所需要的:
ProcessHandle识别并提供对本机进程的控制。可以监视每个单独的进程的活跃度、列出其子进程、获取有关进程的信息或销毁它。相比之下,Process实例由当前进程启动,并额外提供对进程输入、输出和错误流的访问。
因此,如果您可以使用 Java 9 运行您的测试,您可以尝试使用ProcessHandle.allProcesses()找到您想要的进程,然后使用 杀死它.destroy(),使用 监视其活跃度isAlive(),或者使用onExit().
Optional<ProcessHandle> optional = ProcessHandle.allProcesses().filter(process -> {
Optional<String> command = process.info().command();
return command.isPresent() && command.get().equals("Chromedriver.exe");
}).findFirst();
if (optional.isPresent()) {
ProcessHandle processHandle = optional.get();
System.out.println("Killing process " + processHandle.pid());
processHandle.destroy();
try {
System.out.println("Waiting for process " + processHandle.pid() + " to exit...");
processHandle.onExit().get();
System.out.println("Done !");
} catch (InterruptedException|ExecutionException e) {
e.printStackTrace();
}
}
Run Code Online (Sandbox Code Playgroud)
话虽如此,如果您真的想要,您可以Process自己创建一个子类,它将提供有限的功能(即与 I/O 无关,只有waitFor等等destroy)。
下面是一个可怕的例子,它使用这个 Q&A中的想法为 Windows 实现快速破解。
tasklist /FO CSV /FI "IMAGENAME eq Chromedriver.exe", to get the PIDtaskkilltasklist
/FO CSV /FI "PID eq ..."Linux版本的使用pgrep,kill和/proc/{pid}/。
请注意,这不是真正有用的包裹,作为一个实际的例子java.lang.Process,所以我分开了工具类的顾虑实现所需功能的Windows,和子类Process作为一个练习来实现显示什么是可能的,什么是不可能(代码中的详细信息)。因此,如果您需要,最好ProcessTool直接使用,而不是DummyProcess.
(我已经在另一个过程中对此进行了测试,我不能说Chromedriver.exe,您可能需要调整一些细节)
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Paths;
import java.util.Scanner;
public class WaitForProcessDemo {
public static void main(String[] args) throws IOException, InterruptedException {
Process p = getDummyProcess("Chromedriver");
System.out.println("Killing...");
p.destroy();
System.out.println("Waiting...");
p.waitFor();
System.out.println("Done.");
}
private static Process getDummyProcess(String exeName) throws IOException {
ProcessTool tool = new WindowsProcessTool();
long pid = tool.findProcessByName(exeName);
return new DummyProcess(pid, tool);
}
interface ProcessTool {
long findProcessByName(String exeName) throws IOException;
void killProcess(long pid) throws IOException;
boolean isPidStillThere(long pid);
}
private static class WindowsProcessTool implements ProcessTool {
@Override
public long findProcessByName(String exeName) throws IOException {
String processInfoCSV = findProcessInfoCSV("IMAGENAME eq " + exeName);
String[] fields = processInfoCSV.split("\"");
String pid = fields[3];
return Integer.parseInt(pid);
}
String findProcessInfoCSV(String filter) throws IOException {
Process p = new ProcessBuilder("tasklist", "-FO", "CSV", "/FI", filter)
.redirectErrorStream(true)
.start();
Scanner scanner = new Scanner(p.getInputStream());
scanner.nextLine(); // skip header line
if (scanner.hasNextLine()) {
return scanner.nextLine();
}
throw new IOException("No such process: " + filter);
}
@Override
public void killProcess(long pid) throws IOException {
new ProcessBuilder("taskkill", "/PID", String.valueOf(pid))
.redirectErrorStream(true)
.start();
}
@Override
public boolean isPidStillThere(long pid) {
try {
findProcessInfoCSV("PID eq " + pid);
return true;
} catch (IOException e) {
return false;
}
}
}
private static class LinuxProcessTool implements ProcessTool {
@Override
public long findProcessByName(String exeName) throws IOException {
Process pgrep = new ProcessBuilder("pgrep", exeName)
.redirectErrorStream(true)
.start();
Scanner scanner = new Scanner(pgrep.getInputStream());
return Long.parseLong(scanner.nextLine());
}
@Override
public void killProcess(long pid) throws IOException {
new ProcessBuilder("kill", String.valueOf(pid))
.redirectErrorStream(true)
.start();
}
@Override
public boolean isPidStillThere(long pid) {
return Paths.get("/proc", String.valueOf(pid)).toFile().isDirectory();
}
}
/*
* Broken & incomplete implementation of java.lang.Process, implemented as an exercise.
* (Kids, don't do this at home)
*/
static class DummyProcess extends Process {
private final long pid;
private final ProcessTool tool;
DummyProcess(long pid, ProcessTool tool) {
this.pid = pid;
this.tool = tool;
}
@Override
public OutputStream getOutputStream() {
return null; // DANGER. This cannot be implemented for non-child process.
}
@Override
public InputStream getInputStream() {
return null; // DANGER. This cannot be implemented for non-child process.
}
@Override
public InputStream getErrorStream() {
return null; // DANGER. This cannot be implemented for non-child process.
}
@Override
public int waitFor() throws InterruptedException {
// Very sub-optimal implementation
boolean isPidPresent = isPidStillThere();
while (isPidPresent) {
Thread.sleep(500);
isPidPresent = isPidStillThere();
}
return 0;
}
@Override
public int exitValue() {
// For example, this is dangerous, as Process.isAlive() will call this, and determine process is not alive.
// Also, it cannot be implemented correctly, it's not possible to tell what was exit value.
// At best we could throw IllegalThreadStateException when process is still alive.
return 0;
}
@Override
public void destroy() {
try {
tool.killProcess(pid);
} catch (IOException e) {
throw new RuntimeException("Failed to kill process " + pid, e);
}
}
private boolean isPidStillThere() {
return tool.isPidStillThere(pid);
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
871 次 |
| 最近记录: |