论坛首页 Java企业应用论坛

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

浏览 2738 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2013-05-21  
我们在开发中经常会遇到这样的问题,需要把本地运行的所有某个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可用于解决常见的问题。
但是做为一个有追求的程序员 ,我们不禁要想,jps是怎么实现的呢,也是根据不同的平台使用不同的命令吗?
抱着这样的态度,我们可以查看下OpenJDK中jps的源码。看过之后会恍然大悟:原来是这样的。

***

每启动一个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的实现,原来并不是在不同的系统执行不同的命令,哈哈

论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics