获取当前用户所有java进程及jps命令的实现

我们在开发中经常会遇到这样的问题,需要把本地运行的所有某个Java应用找出来,以便于执行某种操作。所以,常见的想法是在不同的平台采用不同的实现方式:
在windows下使用netstat,linux下使用ps -ef。相对来说linux下更方便,因为ps -ef可以把详细的jvm参数和文件路径也列出来,更方便程序操作。当然,如果你使用过java的jps工具的话,感觉会更方便。
jps的usage:


usage: jps [-help]
jps [-q] [-mlvV] [<hostid>]

Definitions:
<hostid>: <hostname>[:<port>]

只需要在命令行中输入jps,就会列出当前用户的所有java进程。
当然,标准的输出只有pid和Main Class的名称。加上具体的参数 -l会列出Main Class的完整类名,再加上-v,会列出详细的jvm参数:
例如:

6544 sun.tools.jps.Jps -Dapplication.home=C:\Program Files (x86)\Java\jdk1.6.0_4
5 -Xms8m
3920 sun.tools.jconsole.JConsole -Dapplication.home=D:\Java\jdk1.6.0_10 -Djconso
le.showOutputViewer


根据完整的类名,pid可用于解决常见的问题。
但是做为一个有追求的程序员 :oops: ,我们不禁要想,jps是怎么实现的呢,也是根据不同的平台使用不同的命令吗?
抱着这样的态度,我们可以查看下OpenJDK中jps的源码。看过之后会恍然大悟:原来是这样的。 8)

***

每启动一个java应用,其会在当前用户的临时目录下创建一个临时文件,以该应用的pid命名。


public static final String dirNamePrefix = "hsperfdata_";
public static String getTempDirectory(String user) {
return tmpDirName + dirNamePrefix + user + File.separator;
}
在windows中,如果没有设置java.io.tmpdir,则会在C:\Users\UserName\AppData\Local\Temp\hsperfdata_UserName\目录下创建xxx(pid)

jps则会根据这些文件,获取本地的java进程,及具体的Main CLass 名称等。
获取代码:
Jps

try {
HostIdentifier hostId = arguments.hostId();
MonitoredHost monitoredHost =
MonitoredHost.getMonitoredHost(hostId);

// get the set active JVMs on the specified host.
Set jvms = monitoredHost.activeVms();

for (Iterator j = jvms.iterator(); j.hasNext(); /* empty */ ) {
StringBuilder output = new StringBuilder();
Throwable lastError = null;

int lvmid = ((Integer)j.next()).intValue();

output.append(String.valueOf(lvmid));

if (arguments.isQuiet()) {
System.out.println(output);
continue;
}

MonitoredVm vm = null;
String vmidString = "//" + lvmid + "?mode=r";

try {
VmIdentifier id = new VmIdentifier(vmidString);
vm = monitoredHost.getMonitoredVm(id, 0);
} catch (URISyntaxException e) {
// unexpected as vmidString is based on a validated hostid
lastError = e;
assert false;
} catch (Exception e) {
lastError = e;
} finally {
if (vm == null) {
/*
* we ignore most exceptions, as there are race
* conditions where a JVM in 'jvms' may terminate
* before we get a chance to list its information.
* Other errors, such as access and I/O exceptions
* should stop us from iterating over the complete set.
*/
output.append(" -- process information unavailable");
if (arguments.isDebug()) {
if ((lastError != null)
&& (lastError.getMessage() != null)) {
output.append("\n\t");
output.append(lastError.getMessage());
}
}
System.out.println(output);
if (arguments.printStackTrace()) {
lastError.printStackTrace();
}
continue;
}
}

output.append(" ");
output.append(MonitoredVmUtil.mainClass(vm,
arguments.showLongPaths()));
以下是activeVMs方法的代码:
/**
* Return the current set of monitorable Java Virtual Machines.
* <p>
* The set returned by this method depends on the user name passed
* to the constructor. If no user name was specified, then this
* method will return all candidate JVMs on the system. Otherwise,
* only the JVMs for the given user will be returned. This assumes
* that principal associated with this JVM has the appropriate
* permissions to access the target set of JVMs.
*
* @return Set - the Set of monitorable Java Virtual Machines
*/
public synchronized Set<Integer> activeVms() {
/*
* This method is synchronized because the Matcher object used by
* fileFilter is not safe for concurrent use, and this method is
* called by multiple threads. Before this method was synchronized,
* we'd see strange file names being matched by the matcher.
*/
Set<Integer> jvmSet = new HashSet<Integer>();

if (! tmpdir.isDirectory()) {
return jvmSet;
}

if (userName == null) {
/*
* get a list of all of the user temporary directories and
* iterate over the list to find any files within those directories.
*/
File[] dirs = tmpdir.listFiles(userFilter);

for (int i = 0 ; i < dirs.length; i ++) {
if (!dirs[i].isDirectory()) {
continue;
}

// get a list of files from the directory
File[] files = dirs[i].listFiles(fileFilter);

if (files != null) {
for (int j = 0; j < files.length; j++) {
if (files[j].isFile() && files[j].canRead()) {
jvmSet.add(new Integer(
PerfDataFile.getLocalVmId(files[j])));
}
}
}
}
} else {
/*
* Check if the user directory can be accessed. Any of these
* conditions may have asynchronously changed between subsequent
* calls to this method.
*/

// get the list of files from the specified user directory
File[] files = tmpdir.listFiles(fileFilter);

if (files != null) {
for (int j = 0; j < files.length; j++) {
if (files[j].isFile() && files[j].canRead()) {
jvmSet.add(new Integer(
PerfDataFile.getLocalVmId(files[j])));
}
}
}
}

// look for any 1.4.1 files
File[] files = tmpdir.listFiles(tmpFileFilter);
if (files != null) {
for (int j = 0; j < files.length; j++) {
if (files[j].isFile() && files[j].canRead()) {
jvmSet.add(new Integer(
PerfDataFile.getLocalVmId(files[j])));
}
}
}

return jvmSet;
}
}

通过这些,明白了jps的实现,原来并不是在不同的系统执行不同的命令,哈哈
发布了56 篇原创文章 · 获赞 0 · 访问量 7785

猜你喜欢

转载自blog.csdn.net/chainhou/article/details/84433779