openjdk-jps源码分析

jps工具用来列举系统中正在运行的java进程,和unix命令ps类似。

命令格式

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

Definitions:
    <hostid>:      <hostname>[:<port>]
  • -q选项:不输出类名,JAR文件名称和应用程序主方法的参数,仅列出pid。
  • -m选项:输出传递到应用程序主方法的参数。
  • -l选项:输出应用程序主类的完整包名。
  • -v选项:输出虚拟机参数
  • -V选项:输出通过标识文件传递给虚拟机的参数。

源码路径

openjdk/jdk/src/share/classes/sun/tools/jps/Jps.java
openjdk/jdk/src/share/classes/sun/tools/jps/Arguments.java

源码

package sun.tools.jps;

import java.util.*;
import java.net.*;
import sun.jvmstat.monitor.*;

/**
 * Application to provide a listing of monitorable java processes.
 *
 * @author Brian Doherty
 * @since 1.5
 */
public class Jps {

    private static Arguments arguments;

    public static void main(String[] args) {
        //命令行参数判断
        try {
            arguments = new Arguments(args);
        } catch (IllegalArgumentException e) {
            System.err.println(e.getMessage());
            Arguments.printUsage(System.err);
            System.exit(1);
        }
        
        //命令行参数判断
        if (arguments.isHelp()) {
            Arguments.printUsage(System.err);
            System.exit(0);
        }

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

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

            for (Integer jvm: jvms) {
                StringBuilder output = new StringBuilder();
                Throwable lastError = null;

                int lvmid = jvm;

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

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

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

                String errorString = null;

                try {
                    // Note: The VM associated with the current VM id may
                    // no longer be running so these queries may fail. We
                    // already added the VM id to the output stream above.
                    // If one of the queries fails, then we try to add a
                    // reasonable message to indicate that the requested
                    // info is not available.

                    errorString = " -- process information unavailable";
                    VmIdentifier id = new VmIdentifier(vmidString);
/*
获得MonitorVm,并且创建了perfData缓存。
MonitorVm通过解析目标主机的PerfData共享数据,
将PerfData数据写入Man<String,Monitor>中,
这个map称为monitors<PerfDataBufferImpl类成员变量>
*/
                    vm = monitoredHost.getMonitoredVm(id, 0);

                    //这部分为对命令行参数结果的最终展示,调用了MonitoredVmUtil类
                    errorString = " -- main class information unavailable";
                    output.append(" " + MonitoredVmUtil.mainClass(vm,
                            arguments.showLongPaths()));

                    if (arguments.showMainArgs()) {
                        errorString = " -- main args information unavailable";
                        String mainArgs = MonitoredVmUtil.mainArgs(vm);
                        if (mainArgs != null && mainArgs.length() > 0) {
                            output.append(" " + mainArgs);
                        }
                    }
                    if (arguments.showVmArgs()) {
                        errorString = " -- jvm args information unavailable";
                        String jvmArgs = MonitoredVmUtil.jvmArgs(vm);
                        if (jvmArgs != null && jvmArgs.length() > 0) {
                          output.append(" " + jvmArgs);
                        }
                    }
                    if (arguments.showVmFlags()) {
                        errorString = " -- jvm flags information unavailable";
                        String jvmFlags = MonitoredVmUtil.jvmFlags(vm);
                        if (jvmFlags != null && jvmFlags.length() > 0) {
                            output.append(" " + jvmFlags);
                        }
                    }

                    errorString = " -- detach failed";
                    monitoredHost.detach(vm);

                    System.out.println(output);

                    errorString = null;
                } catch (URISyntaxException e) {
                    // unexpected as vmidString is based on a validated hostid
                    lastError = e;
                    assert false;
                } catch (Exception e) {
                    lastError = e;
                } finally {
                    if (errorString != 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(errorString);
                        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;
                    }
                }
            }
        } catch (MonitorException e) {
            if (e.getMessage() != null) {
                System.err.println(e.getMessage());
            } else {
                Throwable cause = e.getCause();
                if ((cause != null) && (cause.getMessage() != null)) {
                    System.err.println(cause.getMessage());
                } else {
                    e.printStackTrace();
                }
            }
            System.exit(1);
        }
    }
}

         从main()函数可以看出,jps利用了辅助工具类MonitoredVmUtil,获得展示信息。MonitoredVmUtil.java中实现了一些列获得虚拟机监视器信息的接口方法,这些方法通过读取并解析共享内存PerfMemory的命名变量,能够捕获虚拟机监视器信息。

  • "java.property.java.vm.version"  :虚拟机版本
  • "sun.rt.javaCommand":命令行
  • "java.rt.vmArgs":虚拟机参数
  • "java.rt.vmFlags":虚拟机选项
  • ......

【路径:openjdk/jdk/src/share/classes/sun/jvmstat/monitor/MonitoredVmUtil.java】 

根据监视器名称获取指定监视器,有两种查找方法, 分别为findByName()函数[通过完整的monitor名称查找], 和findByPattern()函数[通过正则查找]。 

    public static String vmVersion(MonitoredVm vm) throws MonitorException {
        StringMonitor ver =
               (StringMonitor)vm.findByName("java.property.java.vm.version");
        return (ver == null) ? "Unknown" : ver.stringValue();
    }

    public static String commandLine(MonitoredVm vm) throws MonitorException {
        StringMonitor cmd = (StringMonitor)vm.findByName("sun.rt.javaCommand");
        return (cmd == null) ? "Unknown" : cmd.stringValue();
    }

    public static String jvmArgs(MonitoredVm vm) throws MonitorException {
        StringMonitor jvmArgs = (StringMonitor)vm.findByName("java.rt.vmArgs");
        return (jvmArgs == null) ? "Unknown" : jvmArgs.stringValue();
    }

    public static String jvmFlags(MonitoredVm vm) throws MonitorException {
        StringMonitor jvmFlags =
               (StringMonitor)vm.findByName("java.rt.vmFlags");
        return (jvmFlags == null) ? "Unknown" : jvmFlags.stringValue();
    }

结束语

        除了上述监视器之外,还有一些隐藏的监视器,所以可以通过修改openjdk源码,扩展jps的功能,获取更多信息。下一篇文章将详细讲解如何扩展jps功能。

  • 13
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值