不用重新配置,用jconsole连接远程机器进程及获得本地进程的JMX Url的终极办法

简介:

估计有很多人都在想用jconsole连接远程机器上的进程时,发现没有配置jmx端口,或者其它的东东。

下面介始一种很简单的办法,可以不用重启远程机器的进程:

ssh -X  192.168.66.66  -l username


连接上去之后,可以直接运行jconsole进程,然后在本机就会弹出一个jconsole的窗口了。

实际上这个不是用jconsole连接远程机器的进程,而是把远程机器上的X输出转地本地来。

如果有提示失败,那么可能要配置下ssh可以转发X。


=====================================

但是如果是想用编程的方式去连接本地的Java进程,而又不能更改配置重启。

比如你有个程序是用jmx的方式去得到监控数据的,那么肯定不能重启目标进程,如druid的StatViewServlet:

https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_StatViewServlet%E9%85%8D%E7%BD%AE


可以用下面的方法来得到本地进程的jmx url。

在以前的博客《查找本地进程的jmx url的代码》里有提到ActiveMQ里获得本地进程的jmx url的方法。

http://blog.csdn.net/hengyunabc/article/details/8938281

这个方法有时却不起效,得到的是null,但是用jconsole却又能连接。于是研究了下jconsole的源代码,终于发现,原来jconsole在得不到目标进程的"com.sun.management.jmxremote.localConnectorAddress"环境变量值时,会先尝试让目标进程加载management-agent.jar,这样就可以得到jmx url了。

jconsole的相关源代码OpenJDK源代码下面的 jdk/src/share/classes/sun/tools/jconsole/LocalVirtualMachine.java 里。可以在这里直接看到:

http://hg.openjdk.java.net/jdk7/jdk7/jdk/file/9b8c96f96a0f/src/share/classes/sun/tools/jconsole/LocalVirtualMachine.java


下面是改进后的得到本地进程jmx url的代码,对于异常的处理不是很完善,不过不影响使用:

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
import java.util.Properties;

public class AbstractJmxCommand  {
    private static final String CONNECTOR_ADDRESS =
        "com.sun.management.jmxremote.localConnectorAddress";

    public static String getJVM() {
        return System.getProperty("java.vm.specification.vendor");
    }

    public static boolean isSunJVM() {
        // need to check for Oracle as that is the name for Java7 onwards.
        return getJVM().equals("Sun Microsystems Inc.") || getJVM().startsWith("Oracle");
    }
    
    public static void main(String[] args) {
		if (args == null || args.length == 0) {
			System.out.println("Usage: pid");
			return;
		}
		int pid = Integer.parseInt(args[0]);
		System.out.println(new AbstractJmxCommand().findJMXUrlByProcessId(pid));
	}
    /**
     * Finds the JMX Url for a VM by its process id
     *
     * @param pid
     * 		The process id value of the VM to search for.
     *
     * @return the JMX Url of the VM with the given pid or null if not found.
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    protected String findJMXUrlByProcessId(int pid) {

        if (isSunJVM()) {
            try {
                // Classes are all dynamically loaded, since they are specific to Sun VM
                // if it fails for any reason default jmx url will be used

                // tools.jar are not always included used by default class loader, so we
                // will try to use custom loader that will try to load tools.jar

                String javaHome = System.getProperty("java.home");
                String tools = javaHome + File.separator +
                        ".." + File.separator + "lib" + File.separator + "tools.jar";
                URLClassLoader loader = new URLClassLoader(new URL[]{new File(tools).toURI().toURL()});

                Class virtualMachine = Class.forName("com.sun.tools.attach.VirtualMachine", true, loader);
                Class virtualMachineDescriptor = Class.forName("com.sun.tools.attach.VirtualMachineDescriptor", true, loader);

                Method getVMList = virtualMachine.getMethod("list", (Class[])null);
                Method attachToVM = virtualMachine.getMethod("attach", String.class);
                Method getAgentProperties = virtualMachine.getMethod("getAgentProperties", (Class[])null);
                Method getVMId = virtualMachineDescriptor.getMethod("id",  (Class[])null);

                List allVMs = (List)getVMList.invoke(null, (Object[])null);

                for(Object vmInstance : allVMs) {
                    String id = (String)getVMId.invoke(vmInstance, (Object[])null);
                    if (id.equals(Integer.toString(pid))) {

                        Object vm = attachToVM.invoke(null, id);

                        Properties agentProperties = (Properties)getAgentProperties.invoke(vm, (Object[])null);
                        String connectorAddress = agentProperties.getProperty(CONNECTOR_ADDRESS);

                        if (connectorAddress != null) {
                            return connectorAddress;
                        } else {
                            break;
                        }
                    }
                }
                
                //上面的尝试都不成功,则尝试让agent加载management-agent.jar
                Method getSystemProperties = virtualMachine.getMethod("getSystemProperties", (Class[])null);
                Method loadAgent = virtualMachine.getMethod("loadAgent", String.class, String.class);
                Method detach = virtualMachine.getMethod("detach", (Class[])null);
                for(Object vmInstance : allVMs) {
                    String id = (String)getVMId.invoke(vmInstance, (Object[])null);
                    if (id.equals(Integer.toString(pid))) {

                        Object vm = attachToVM.invoke(null, id);

                        Properties systemProperties = (Properties)getSystemProperties.invoke(vm, (Object[])null);
                        String home = systemProperties.getProperty("java.home");
                        
                        // Normally in ${java.home}/jre/lib/management-agent.jar but might
                        // be in ${java.home}/lib in build environments.

                        String agent = home + File.separator + "jre" + File.separator +
                                           "lib" + File.separator + "management-agent.jar";
                        File f = new File(agent);
                        if (!f.exists()) {
                            agent = home + File.separator +  "lib" + File.separator +
                                        "management-agent.jar";
                            f = new File(agent);
                            if (!f.exists()) {
                                throw new IOException("Management agent not found");
                            }
                        }
                        
                        agent = f.getCanonicalPath();
                        
                        loadAgent.invoke(vm, agent, "com.sun.management.jmxremote");
                        
                        Properties agentProperties = (Properties)getAgentProperties.invoke(vm, (Object[])null);
                        String connectorAddress = agentProperties.getProperty(CONNECTOR_ADDRESS);

                        //detach 这个vm
                        detach.invoke(vm, (Object[])null);
                        
                        if (connectorAddress != null) {
                            return connectorAddress;
                        } else {
                            break;
                        }
                    }
                }
            } catch (Exception ignore) {
            	System.err.println(ignore);
            }
        }

        return null;
    }
}


目录
打赏
0
0
0
0
38
分享
相关文章
"如何使用 jconsole 查看Java进程中线程的详细信息? "
当Java程序运行时,其中的一些线程也正在执行。我们可以用第三方工具 jconsole 来查看Java进程中线程的执行情况和详细信息,这有助于我们对多线程编程的理解。
262 0
jconsole远程监控linux上的java进程
jconsole远程监控linux上的java进程
918 0
不用重新配置,用jconsole连接远程机器进程及获得本地进程的JMX Url的终极办法
估计有很多人都在想用jconsole连接远程机器上的进程时,发现没有配置jmx端口,或者其它的东东。 下面介始一种很简单的办法,可以不用重启远程机器的进程: ssh -X  192.168.66.66  -l username 连接上去之后,可以直接运行jconsole进程,然后在本机就会弹出一个jconsole的窗口了。
918 0
探索Linux中的`ps`命令:进程监控与分析的利器
探索Linux中的`ps`命令:进程监控与分析的利器
170 13
掌握taskset:优化你的Linux进程,提升系统性能
在多核处理器成为现代计算标准的今天,运维人员和性能调优人员面临着如何有效利用这些处理能力的挑战。优化进程运行的位置不仅可以提高性能,还能更好地管理和分配系统资源。 其中,taskset命令是一个强大的工具,它允许管理员将进程绑定到特定的CPU核心,减少上下文切换的开销,从而提升整体效率。
掌握taskset:优化你的Linux进程,提升系统性能
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
225 4
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
探索进程调度:Linux内核中的完全公平调度器
【8月更文挑战第2天】在操作系统的心脏——内核中,进程调度算法扮演着至关重要的角色。本文将深入探讨Linux内核中的完全公平调度器(Completely Fair Scheduler, CFS),一个旨在提供公平时间分配给所有进程的调度器。我们将通过代码示例,理解CFS如何管理运行队列、选择下一个运行进程以及如何对实时负载进行响应。文章将揭示CFS的设计哲学,并展示其如何在现代多任务计算环境中实现高效的资源分配。
【Linux】冯诺依曼体系结构与操作系统及其进程
【Linux】冯诺依曼体系结构与操作系统及其进程
209 1
【编程小实验】利用Linux fork()与文件I/O:父进程与子进程协同实现高效cp命令(前半文件与后半文件并行复制)
这个小程序是在文件IO的基础上去结合父子进程的一个使用,利用父子进程相互独立的特点实现对数据不同的操作
154 2
【Linux开发实战指南】基于TCP、进程数据结构与SQL数据库:构建在线云词典系统(含注册、登录、查询、历史记录管理功能及源码分享)
TCP(Transmission Control Protocol)连接是互联网上最常用的一种面向连接、可靠的、基于字节流的传输层通信协议。建立TCP连接需要经过著名的“三次握手”过程: 1. SYN(同步序列编号):客户端发送一个SYN包给服务器,并进入SYN_SEND状态,等待服务器确认。 2. SYN-ACK:服务器收到SYN包后,回应一个SYN-ACK(SYN+ACKnowledgment)包,告诉客户端其接收到了请求,并同意建立连接,此时服务器进入SYN_RECV状态。 3. ACK(确认字符):客户端收到服务器的SYN-ACK包后,发送一个ACK包给服务器,确认收到了服务器的确
226 1

热门文章

最新文章

相关实验场景

更多
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等