1. 概述

在这个教程中,我们将解释为什么JMX在启动时会打开三个端口。此外,我们将演示如何在Java中启动JMX,并展示如何限制打开的端口号。

2. JMX定义

首先,让我们定义一下JMX框架。Java管理扩展(Java Management Extensions,JMX)框架提供了一个可配置、可扩展且可靠的管理Java应用程序的基础设施。它还定义了MBean的概念,用于实时管理应用程序。该框架允许本地或远程管理应用程序。

3. 在Java中启用JMX

现在,让我们来看看如何启用JMX。对于Java 1.5及更早版本,有一个系统属性 com.sun.management.jmxremote。带有该属性的应用程序可以从本地和远程通过JConsole进行连接。另一方面,如果没有该属性启动的应用程序则不会被JConsole看到。

然而,从Java 6及以上版本开始,这个参数就不再需要了。应用程序在启动后自动可供管理。此外,默认配置会自动分配端口并仅在本地暴露。

4. JMX端口

在我们的示例中,我们将使用Java 6或更高版本。首先,我们创建一个无限循环的类,这个类不做任何事情,但可以用来检查哪些端口是打开的:

public class JMXConfiguration {

    public static void main(String[] args) {
        while (true) {
            // to ensure application does not terminate
        }
    }
}

然后编译并运行这个类:

java com.baeldung.jmx.JMXConfiguration

之后,我们可以检查进程分配的pid,并检查进程打开的端口

netstat -ao | grep <pid>

结果,我们会得到应用程序暴露的端口号列表:

Active Connections
Proto  Local Address          Foreign Address        State           PID
TCP    127.0.0.1:55846        wujek:55845            ESTABLISHED     2604

此外,如果重启应用,端口会发生变化。它会被随机分配。这种功能自Java 6开始可用,它自动为Java Attach API暴露应用程序。换句话说,它自动通过Local Process为JConsole连接提供服务。

现在,让我们通过向JVM提供选项来启用远程连接:

-Dcom.sun.management.jmxremote=true
-Dcom.sun.management.jmxremote.port=1234
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

为了远程连接,我们必须提供端口号作为必选参数。我们禁用认证和SSL只是为了测试目的。

现在,netstat命令返回:

Proto  Local Address    Foreign Address State       PID
TCP    0.0.0.0:1234     wujek:0         LISTENING   11088
TCP    0.0.0.0:58738    wujek:0         LISTENING   11088
TCP    0.0.0.0:58739    wujek:0         LISTENING   11088

如图所示,应用程序暴露了三个端口。RMI/JMX暴露了两个端口,第三个端口是为本地连接随机分配的。

5. 限制打开的端口号数量

首先,我们可以使用-XX:+DisableAttachMechanism选项来禁用JConsole的本地连接:

java -XX:+DisableAttachMechanism com.baeldung.jmx.JMXConfiguration

这样,应用程序就不暴露任何JMX/RMI端口了。

此外,从JDK 16开始,我们可以设置本地端口号:

java 
  -Dcom.sun.management.jmxremote=true 
  -Dcom.sun.management.jmxremote.local.port=1235 
  com.baeldung.jmx.JMXConfiguration

现在,让我们更改配置,处理远程端口。

还有一个选项-Dcom.sun.management.jmxremote.rmi.port=1234,它可以将RMI端口设置为与JMX端口相同的值。完整的命令如下:

java 
  -Dcom.sun.management.jmxremote=true 
  -Dcom.sun.management.jmxremote.port=1234 
  -Dcom.sun.management.jmxremote.rmi.port=1234 
  -Dcom.sun.management.jmxremote.local.port=1235 
  -Dcom.sun.management.jmxremote.authenticate=false 
  -Dcom.sun.management.jmxremote.ssl=false 
  com.baeldung.jmx.JMXConfiguration

之后,netstat命令返回:

Proto  Local Address    Foreign Address State       PID
TCP    0.0.0.0:1234     wujek:0         LISTENING   19504
TCP    0.0.0.0:1235     wujek:0         LISTENING   19504

这意味着应用程序只暴露两个端口:一个用于RMI/JMX的远程连接,另一个用于本地连接。这样,我们可以完全控制暴露的端口,避免与其他进程暴露的端口冲突。

但是,当启用远程连接并禁用attach机制时:

java 
  -XX:+DisableAttachMechanism 
  -Dcom.sun.management.jmxremote=true 
  -Dcom.sun.management.jmxremote.port=1234 
  -Dcom.sun.management.jmxremote.rmi.port=1234 
  -Dcom.sun.management.jmxremote.authenticate=false 
  -Dcom.sun.management.jmxremote.ssl=false 
  com.baeldung.jmx.JMXConfiguration

应用程序仍然暴露两个端口:

Proto Local Address     Foreign Address     State       PID
TCP   0.0.0.0:1234      wujek:0             LISTENING   9856
TCP   0.0.0.0:60565     wujek:0             LISTENING   9856

6. 总结

在这篇短文中,我们解释了如何在Java中启动JMX,展示了JMX启动时打开的端口,并演示了如何限制JMX打开的端口号数量。如往常一样,示例代码可以在GitHub上找到。