【问题标题】:How to programmatically invoke MBeans operation of target process如何以编程方式调用目标进程的 MBeans 操作
【发布时间】:2019-05-28 08:26:30
【问题描述】:

我想通过以下方式模拟jconsole 所做的事情:

  1. 识别暴露 jmx 功能的正在运行的进程(例如:pid: 14796 FreshProject.jar

  2. 列出可用的 MBean 库(例如:org.jacoco

  3. 调用操作(例如:点击dump

我尝试过使用here 中提到的simplejmx 库,但我对应该使用什么hostNameport 感到困惑。我尝试传递localhost1099,因为我读过这些是默认值,但它错误java.net.ConnectException: Connection refused: connect

请不要将我指向其他软帖子并关闭此帖子,因为我很可能已经阅读并尝试了几次。

【问题讨论】:

    标签: java jmx jacoco jconsole mbeans


    【解决方案1】:

    我想模拟 jconsole 的作用

    看看 jconsole 的实现 - 见 http://openjdk.java.net/tools/svc/jconsole/https://github.com/openjdk/jdk/tree/master/src/jdk.jconsole/share/classes

    我对应该使用什么主机名和端口感到困惑。我尝试传递 localhost 和 1099,因为我读过这些是默认值,但它错误 java.net.ConnectException: Connection denied: connect.

    根据https://docs.oracle.com/en/java/javase/11/management/monitoring-and-management-using-jmx-technology.html,默认情况下没有端口。而 JConsole 使用 Attach API - 请参阅 https://github.com/openjdk/jdk/blob/master/src/jdk.jconsole/share/classes/sun/tools/jconsole/LocalVirtualMachine.java 在此代码中,您还将在

    上找到答案

    识别公开 jmx 功能的正在运行的进程

    要通过端口连接,您需要指定适当的参数。比如下面Example.java

    class Example {
        public static void main(String[] args) {
            while (true) {
            }
        }
    }
    

    可以启动为

    java \
        -Dcom.sun.management.jmxremote.port=1099 \
        -Dcom.sun.management.jmxremote.authenticate=false \
        -Dcom.sun.management.jmxremote.ssl=false \
        Example
    

    然后

    列出可用的 MBean

    可以这样做

    import javax.management.MBeanServer;
    import javax.management.MBeanServerConnection;
    import javax.management.MBeanServerInvocationHandler;
    import javax.management.ObjectInstance;
    import javax.management.ObjectName;
    import javax.management.remote.JMXConnector;
    import javax.management.remote.JMXConnectorFactory;
    import javax.management.remote.JMXServiceURL;
    
    import java.lang.management.ManagementFactory;
    import java.util.Iterator;
    import java.util.Set;
    
    class GetMBeans {
        public static void main(final String[] args) throws Exception {
           final JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi");
           final JMXConnector jmxc = JMXConnectorFactory.connect(url, null);
           final MBeanServerConnection connection = jmxc.getMBeanServerConnection();
    
           Set<ObjectInstance> instances = connection.queryMBeans(null, null);
           Iterator<ObjectInstance> iterator = instances.iterator();
           while (iterator.hasNext()) {
               ObjectInstance instance = iterator.next();
               System.out.println(instance.getClassName() + " " + instance.getObjectName());
           }
        }
    }
    

    在上述Example 开始后也与 JaCoCo 一起

    java \
        -Dcom.sun.management.jmxremote.port=1099 \
        -Dcom.sun.management.jmxremote.authenticate=false \
        -Dcom.sun.management.jmxremote.ssl=false \
        -javaagent:jacoco-0.8.4/lib/jacocoagent.jar=jmx=true \
        Example
    

    javac GetMBeans.java &amp;&amp; java GetMBeans | grep jacoco 的执行产生

    org.jacoco.agent.rt.internal_035b120.Agent org.jacoco:type=Runtime
    

    调用操作

    显示在 JaCoCo 文档中 - 请参阅 MBeanClient.java https://www.jacoco.org/jacoco/trunk/doc/api.html

    import javax.management.MBeanServer;
    import javax.management.MBeanServerConnection;
    import javax.management.MBeanServerInvocationHandler;
    import javax.management.ObjectInstance;
    import javax.management.ObjectName;
    import javax.management.remote.JMXConnector;
    import javax.management.remote.JMXConnectorFactory;
    import javax.management.remote.JMXServiceURL;
    
    import java.lang.management.ManagementFactory;
    import java.util.Iterator;
    import java.util.Set;
    
    class MBeanClient {
        public static void main(final String[] args) throws Exception {
           final JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi");
           final JMXConnector jmxc = JMXConnectorFactory.connect(url, null);
           final MBeanServerConnection connection = jmxc.getMBeanServerConnection();
    
           final IProxy proxy = (IProxy) MBeanServerInvocationHandler.newProxyInstance(connection, new ObjectName("org.jacoco:type=Runtime"), IProxy.class, false);
    
           final byte[] data = proxy.getExecutionData(false);
           System.out.println("Got " + data.length + " bytes");
        }
    
        public interface IProxy {
            String getVersion();
            String getSessionId();
            void setSessionId(String id);
            byte[] getExecutionData(boolean reset);
            void dump(boolean reset);
            void reset();
        }
    }
    

    javac MBeanClient.java &amp;&amp; java MBeanClient 的执行产生

    Got 84 bytes
    

    【讨论】:

    • 非常感谢您在此消息中付出的努力。我能够在 5 分钟前做到这一点 - 我已经通过 simplejmx 库完成了它,由于我的 jdk 版本是 8 而不是 10,所以它在过去不起作用。我会接受这个作为答案,因为它主要使用我用过的部分,我也会在我的版本中添加一个答案。
    【解决方案2】:

    请检查链接 - How to get a thread and heap dump of a Java process on Windows that's not running in a console,我在其中发布了一个答案,其中使用 JMX 和反射以编程方式转储堆。您可以将该程序作为示例进行参考。此代码从 JDK 6 开始工作。

    【讨论】:

      【解决方案3】:

      我没有尝试过@Godin 的版本,但我确信它可以正常工作,因为它非常详细。

      我采用了不同的方法:我使用了https://jar-download.com/?search_box=simplejmx 上的simplejmx 库。

      为了将JmxClient 附加到进程,您需要知道它正在运行的端口。它可以通过 JVM 参数来设置:

      -Dcom.sun.management.jmxremote.port=1240
      -Dcom.sun.management.jmxremote.local.only=false
      -Dcom.sun.management.jmxremote.authenticate=false
      -Dcom.sun.management.jmxremote.ssl=false
      

      一旦应用在指定端口上运行,以下脚本将访问它并调用目标操作:

      public static void main(String[] args) throws Exception {
          JmxClient client = new JmxClient("localhost", 1240);
          client.invokeOperation(new ObjectName("org.jacoco:type=Runtime"), "dump", new Object[] {true});
          client.close();
      }
      

      同时检查:How to programmatically check JMX MBean operations and attributes?

      注意:它必须在 jdk 版本 10 或更高版本上。不适用于 8。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-09-17
        • 1970-01-01
        • 1970-01-01
        • 2023-03-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多