java动态执行代码或者第三方程序并返回pid,杀掉进程

使用java动态执行Java代码或者调用第三方软件,如下代码即可

Process child = Runtime.getRuntime().exec(cmd);

只要写好cmd命令即可,如何同时返回进程的pid呢,这样可以准确的杀掉进程,这里我们需要一个jar用于调用dll

java 动态执行groovy语言 java动态执行代码片段_java

网上,maven仓库可下载,或者下载结尾源码

首先把jar buildpath引入,创建一个接口

import com.sun.jna.Library;
import com.sun.jna.Native;

import constant.OtherConstant;

public interface Kernel32 extends Library {
	public static Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);

	public long GetProcessId(Long hProcess);
}

调用方法

// 获取pid
	public static long getProcessPID(Process child) {
		long pid = -1;
		Field field = null;
		try {
			field = child.getClass().getDeclaredField("handle");
			field.setAccessible(true);
			pid = Kernel32.INSTANCE.GetProcessId((Long) field.get(child));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return pid;
	}

接下来实战模拟一下,首先使用runtime执行class文件,书写代码,编译成class,然后使用runtime执行它,示例代码:

package example;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class JavaProcess1 {
	public static void main(String[] args) {
		for (int i = 0; i < 100; i++) {
			System.out.println(i);
//			appendFile("C:\\RICO\\JavaProcess1.txt", "test:  " + i);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	// 追加文件
	public static boolean appendFile(String filePath, String content) {
		FileWriter fw = null;
		try {
			// 如果文件存在,则追加内容
			// 如果文件不存在,则创建文件
			File f = new File(filePath);
			fw = new FileWriter(f, true);
			PrintWriter pw = new PrintWriter(fw);
			pw.println(content);
			pw.flush();
			fw.flush();
			pw.close();
			fw.close();
			return true;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
	}
}

如何编译java执行class详见:,注意有无package名的区别

接下来创建两个工具类,一个是用于执行cmd,一个是线程截取输出流

运行类

package utils;

import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

import constant.OtherConstant;
import constant.SpiderConstant;

public class RunUtils {
	public static Map<String, Object> messageMap = new HashMap<String, Object>();

	// 运行代码有两种方式,一种是通过反射动态运行,一种是另起进程,这里选择另起进程
	public static void run(String cmd, int flag) {
		long pid;
		try {
			Process child = Runtime.getRuntime().exec(cmd);
			messageMap.put(SpiderConstant.SPIDER_KEYWORD_PROCESSMAP_PROCESS, child);

			// 获取此子进程的pid,只windows系统
			pid = getProcessPID(child);
			messageMap.put(SpiderConstant.SPIDER_KEYWORD_PROCESSMAP_PID, pid);

			// 获取程序输入流
			// OutputStream os = child.getOutputStream();
			// 正常输出流和异常输出流
			InputStream stdin = child.getInputStream();
			InputStream stderr = child.getErrorStream();
			// 启动线程,获取输出流

			if (flag == 0) {
				ConsoleSimulator cs1 = new ConsoleSimulator(stdin, 0);
				ConsoleSimulator cs2 = new ConsoleSimulator(stderr, 1);
				Thread tIn = new Thread(cs1);
				Thread tErr = new Thread(cs2);
				tIn.start();
				tErr.start();
			}

			// // 启动线程获取输出之后不在阻塞,直接返回,打印输出以轮播形式推送前台
			// messageMap.put(SpiderConstant.SPIDER_KEYWORD_PROCESSMAP_INPUTSTREAMTHREAD,
			// tIn);
			// messageMap.put(SpiderConstant.SPIDER_KEYWORD_PROCESSMAP_INPUTSTREAMCONSOLE,
			// cs1);
			// messageMap.put(SpiderConstant.SPIDER_KEYWORD_PROCESSMAP_ERRORSTREAMTHREAD,
			// tErr);
			// messageMap.put(SpiderConstant.SPIDER_KEYWORD_PROCESSMAP_ERRORSTREAMCONSOLE,
			// cs2);
			// 正在运行
			messageMap.put(SpiderConstant.SPIDER_KEYWORD_PROCESSMAP_RUNSTATUS, 0);
			// int result = child.waitFor();
			// tIn.join();
			// tErr.join();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// 阻塞
	public static String[] run2(String cmd) {
		String returnPrintContent = null;
		String returnErrorContent = null;
		String[] returnContent = new String[2];
		try {

			Process child = Runtime.getRuntime().exec(cmd);

			// 获取程序输入流
			OutputStream os = child.getOutputStream();
			// 正常输出流和异常输出流
			InputStream stdin = child.getInputStream();
			InputStream stderr = child.getErrorStream();
			// 启动线程

			ConsoleSimulator cs1 = new ConsoleSimulator(stdin, 0);
			ConsoleSimulator cs2 = new ConsoleSimulator(stderr, 1);
			Thread tIn = new Thread(cs1);
			Thread tErr = new Thread(cs2);
			tIn.start();
			tErr.start();
			int result = child.waitFor();
			tIn.join();
			tErr.join();
			returnPrintContent = cs1.getReturnPrintContent();
			returnErrorContent = cs2.getReturnErrorContent();
			// 处理中文乱码,需更改服务器端编码
			// 0是全部信息
			returnContent[0] = returnPrintContent;
			// 1是错误信息
			returnContent[1] = returnErrorContent;
			return returnContent;
		} catch (Exception e) {
			e.printStackTrace();
			return returnContent;
		}
	}

	// 获取pid
	public static long getProcessPID(Process child) {
		long pid = -1;
		Field field = null;
		try {
			field = child.getClass().getDeclaredField("handle");
			field.setAccessible(true);
			pid = Kernel32.INSTANCE.GetProcessId((Long) field.get(child));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return pid;
	}
}

代码中常量信息请下载源码查看

输出流线程

package utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;

import constant.CodingConstant;
import constant.CommonSymbolicConstant;

//另起线程截取程序流
public class ConsoleSimulator implements Runnable {
	public boolean isStop = false;
	public int INFO = 0;
	public int ERROR = 1;
	public InputStream is;
	public int type;
	public StringBuilder returnPrintContent = new StringBuilder();
	public StringBuilder returnErrorContent = new StringBuilder();
	public StringBuilder returnCommonContent = new StringBuilder();

	public ConsoleSimulator(InputStream is, int type) {
		this.is = is;
		this.type = type;
	}

	public void run() {
		InputStreamReader isr = null;
		try {
			isr = new InputStreamReader(is, CodingConstant.CODING_UTF_8);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		BufferedReader reader = new BufferedReader(isr);
		String s;
		try {
			// 此地方执行python的时候阻塞,不知为何线程会停止
			while ((!isStop) && (s = reader.readLine()) != null) {
				if (s.length() != 0) {
					if (type == INFO) {
						System.out.println(s);
						returnPrintContent.append(s + CommonSymbolicConstant.LINEBREAK2);
					} else {
						returnErrorContent.append(s + CommonSymbolicConstant.LINEBREAK2);
					}
				}
			}
			isStop = true;

		} catch (IOException ex) {
			ex.printStackTrace();
		} finally {
			try {
				isr.close();
				reader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public String getReturnPrintContent() {
		return returnPrintContent.toString();
	}

	public String getReturnErrorContent() {
		return returnErrorContent.toString();
	}

	public String getReturnCommonContent() {
		return returnCommonContent.toString();
	}

	public void stop() {
		isStop = true;
	}

}

准备工作完成,开始测试,首先测试无阻塞不获取输出流,注意示例代码运行时长为100秒,我们在运行10秒后杀掉

package runkillprocess;

import constant.CMDConstant;
import constant.SpiderConstant;
import utils.RunUtils;

//使用runtime调用第三方程序
public class RunProcess {
	public static void main(String[] args) {
		// 执行无阻塞调用
		// 子进程动态执行java,class文件
		long pid = runJavaProcess(1);
		System.out.println(pid);

		// 十秒后杀掉进程
		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		stopProcess(pid);

		// 执行阻塞调用

	}

	public static long runJavaProcess(int flag) {
		String cmd = "java -cp C:\\RICO example.JavaProcess1";
		RunUtils.run(cmd, flag);
		// 获取pid
		return (long) RunUtils.messageMap.get("pid");
	}

	public static void stopProcess(long pid) {
		// 拼接命令
		String cmd = "taskkill /PID " + pid + " /F";
		// 运行命令
		String[] returnContent = RunUtils.run2(cmd);
	}
}

若不杀掉进程且不获取输出流,则情况如下:

java 动态执行groovy语言 java动态执行代码片段_java 动态执行groovy语言_02

我们可以看到主程序运行一下就结束了,获取了动态运行的java进行pid为11304,打开任务管理器你会发现11304的进程依然在进行,表明我运行成功。当我们选择10秒后杀掉进程这种情况执行代码,注意管理器中的java进程会在十秒后结束,杀掉成功。

如果选择读取输出流则控制台将会获取跟cmd执行class一样的内容。

下面我们选择一个第三方软件试试。调用notepad++打开一个文件,10秒后杀掉

package runkillprocess;

import constant.CMDConstant;
import constant.SpiderConstant;
import utils.RunUtils;

//使用runtime调用第三方程序
public class RunProcess {
	public static void main(String[] args) {
		// 执行无阻塞调用
		// 子进程调用notepad++,打开一个文件
		long pid = runJavaProcess(1);
		System.out.println(pid);

		// 十秒后杀掉进程
		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		stopProcess(pid);

		// 执行阻塞调用

	}

	public static long runJavaProcess(int flag) {
		String cmd = "\"C:\\Program Files (x86)\\Notepad++\\notepad++.exe\" C:\\RICO\\icon2.txt";
		RunUtils.run(cmd, flag);
		// 获取pid
		return (long) RunUtils.messageMap.get("pid");
	}

	public static void stopProcess(long pid) {
		// 拼接命令
		String cmd = "taskkill /PID " + pid + " /F";
		// 运行命令
		String[] returnContent = RunUtils.run2(cmd);
	}
}

java 动态执行groovy语言 java动态执行代码片段_输出流_03

java 动态执行groovy语言 java动态执行代码片段_java_04

完美运行。

github源码:https://github.com/ricozhou/runkillprocess