如何以编程方式调用目标进程的MBean操作

时间:2019-05-28 08:26:31

标签: java jmx jacoco jconsole mbeans

我想模拟jconsole的作用:

  1. 标识一个正在运行的进程,该进程公开了jmx功能(例如:pid: 14796 FreshProject.jar

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

  3. 调用操作(例如,单击dump

MBeans Operation example

我已经尝试使用here所述的simplejmx库,但是对于应该使用什么hostNameport感到困惑。我已尝试通过传递localhost1099,因为我已阅读它们是默认值,但它错误了java.net.ConnectException: Connection refused: connect

请不要将我指向其他类似的文章,并关闭该文章,因为我很可能已经阅读并尝试了几次。

3 个答案:

答案 0 :(得分: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:连接被拒绝: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 && java GetMBeans | grep jacoco会产生

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

调用操作

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

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 && java MBeanClient会产生

Got 84 bytes

答案 1 :(得分:1)

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

答案 2 :(得分:0)

我没有尝试过@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。