不用重新配置,用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;
    }
}
时间: 2024-08-29 11:53:13

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

PL/SQL连接远程数据库

1.利用ORACLE NET MANAGER工具  1)打开 ORACLE NET MANAGER  2)增加"服务命名"  第一步 NET服务名:任意填写  第二步 通讯协议:如果连接远程机器上的ORACLE,选择TCP/IP(internet协议)  第三步 主机名:输入IP地址 端口号:一般缺省为1521  第四步 SID: 一般和数据库名字相同  第五步 测试  3)启动PL/SQL连接   2.直接修改配置文件:  1)打开目录D:/oracle安装目录/ora92/netw

远程连接-本地连接远程服务器数据库的问题

问题描述 本地连接远程服务器数据库的问题 本地应用phpstudy搭建的,php访问数据库正常.远程连接出问题.空间和数据库是申请万网的.我扫了一下数据库服务地址发现3306端口没有开放.请问:1,我是不是必须要联系运营商开放3306端口?2,我网站后台是linux系统,数据库服务器和后台并非一个ip地址..所以我不清楚的是php中连接数据库会因为操作系统不同而致使访问程序不同吗?3,我看了一些关于数据库授权的材料但是不深入,请问授权能够解决""连接不上服务器响应超时"&qu

在Vista配置SSAS通过HTTP远程连接的方法.

Analysis Services不同于数据引擎有自己的sa方式的验证,而我们在实际生产环境部署的时候不可能应用程序服务器和分析服务器都在同一台物理机器上,这个时候就需要配置分析服务的远程方式访问.目前网上资料最多的就是通过http的方式,本文主要描述sqlserver 2005 analysis services在vista平台下的配置方法. 本文是参考: http://bloggingabout.net/blogs/mglaser/archive/2008/08/15/configuring

IIS7下配置SSAS通过HTTP远程连接

原文:IIS7下配置SSAS通过HTTP远程连接 安装环境操作系统:Windows7.Windows Server2008IIS版本:7.5 IIS7下配置SSAS通过HTTP远程连接详细的步骤如下:1.首先到分析服务器的SQLServer安装目录中找到如下目录和文件,路径如下:D:\Program Files\Microsoft SQL Server\MSAS10_50.MSSQLSERVER\OLAP\bin\isapi 2.在D盘新建一个olap文件,把上述的isapi内的所有东西全部co

sqlplus连接远程数据库

方式一:简易连接,不用进行网络配置,其实就是tnsname.ora文件,但只支持oracle10G以上. 命令:sqlplus 用户名/密码@ip地址[:端口]/service_name [as sysdba] 示例:sqlplus sys/pwd@ip:1521/test as sysdba (注意这里的test是tnsnames.ora中的SERVICE_NAME,而非其它) 备注:使用默认1521端口时可省略输入 方式二:进行网络配置 oracle11和以前的版本 2.1图形化操作:Net

SQL Server 出现Error: 1326错误(管理器无法连接远程数据库)问题解决方案_Mysql

SQL Server 出现Error: 1326错误 我们在在使用SQL Server时都会遇到使用SQL Server Management Studio无法连接远程数据库实例的问题,错误描述信息摘录如下: An error has occurred while establishing a connection to the server. (provider: Named Pipes Provider, error: 40 – Could not open a connection to

CentOS上配置rsyslog客户端用以远程记录日志

CentOS上配置rsyslog客户端用以远程记录日志 rsyslog是一个开源工具,被广泛用于Linux系统以通过TCP/UDP协议转发或接收日志消息.rsyslog守护进程可以被配置成两种环境,一种是配置成日志收集服务器,rsyslog进程可以从网络中收集其它主机上的日志数据,这些主机会将日志配置为发送到另外的远程服务器.rsyslog的另外一个用法,就是可以配置为客户端,用来过滤和发送内部日志消息到本地文件夹(如/var/log)或一台可以路由到的远程rsyslog服务器上. 假定你的网络

优化配置让Windows 2003远程桌面更好地发挥作用

远程桌面连接组件是从Windows 2000 Server开始由微软公司提供的,在WINDOWS 2000 SERVER中他不是默认安装的.该组件一经推出受到了很多用户的拥护和喜好,所以在WINDOWS XP和http://www.aliyun.com/zixun/aggregation/19058.html">2003中微软公司将该组件的启用方法进行了改革,我们通过简单的勾选就可以完成在XP和2003下远程桌面连接功能的开启. 当某台计算机开启了远程桌面连接功能后我们就可以在网络的另一端

C#实现远程机器管理

原文:C#实现远程机器管理      目前处于待离职状态,原先所有的工作都在进行交接,过程当中不乏有很多先前整理的和动手尝试实现的功能:我的主页中已经列出来一部分内容,有兴趣的可以前往看一看.           接下来的内容主要介绍另外一个工具,用于对远程主机进行远程控制.进程管理.服务管理以及WMI相关信息显示等:其中仍然存在部分问题还没有得到有效的解决,希望曾经参与过或者有关相关经验的前辈能够指导一下. 一.很搓很搓的主界面 1.配置菜单里面包括远程主机连接配置信息的添加和编辑,界面如下: