在实际生产环境下,使用RMI实现JMX会受到来自防火墙的诸多限制,替代的方案就是使用JMXMP协议。核心代码实现如下:


JMX服务端:

        final String protocol = "jmxmp";
        final String host = "192.168.1.6";
        final int port = 12345;
        final String serverKeyStoreFile = appBase + "/config/jmxkey/server.keystore";  
        final String serverKeyStorePwd = "storepass";  
        final String serverKeyPwd = "keypass";  
        final String serverTrustKeyStoreFile = appBase + "/config/jmxkey/servertrust.keystore";  
        final String serverTrustKeyStorePwd = "truststorepass";  

        // 创建MBeanServer
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();

        // 创建并注册MBean
        final String domain = "app";
        final String className = AppInfo.class.getName();
        final String name = domain + ":" + "name=" + className;
        final ObjectName objectName = ObjectName.getInstance(name);
        mbs.createMBean(className, objectName);

        // 创建SSLSocketFactory
        KeyStore serverKeyStore = KeyStore.getInstance("JKS");
        serverKeyStore.load(new FileInputStream(serverKeyStoreFile),
                serverKeyStorePwd.toCharArray());
        
        KeyStore serverTrustKeyStore = KeyStore.getInstance("JKS");
        serverTrustKeyStore.load(new FileInputStream(serverTrustKeyStoreFile),
                serverTrustKeyStorePwd.toCharArray());
        
        KeyManagerFactory kmf = KeyManagerFactory
                .getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(serverKeyStore, serverKeyPwd.toCharArray());
        
        TrustManagerFactory tmf = TrustManagerFactory
                .getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(serverTrustKeyStore);

        SSLContext sslContext = SSLContext.getInstance("TLSv1");
        sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
        SSLSocketFactory ssf = sslContext.getSocketFactory();

        // 创建JMX服务器
        Map<String, Object> env = new HashMap<>();
        env.put("jmx.remote.profiles", "TLS");
        env.put("jmx.remote.tls.socket.factory", ssf);
        env.put("jmx.remote.tls.enabled.protocols", "TLSv1");
        env.put("jmx.remote.tls.enabled.cipher.suites",
                "SSL_RSA_WITH_3DES_EDE_CBC_SHA");
        JMXServiceURL url = new JMXServiceURL(protocol, host, port);
        JMXConnectorServer cs = JMXConnectorServerFactory
                .newJMXConnectorServer(url, env, mbs);
        cs.start();


JMX客户端:

        final String protocol = "jmxmp";
        final String host = "192.168.1.6";
        final int port = 12345;
        final String clientKeyStoreFile = appBase + "/config/jmxkey/client.keystore";  
        final String clientKeyStorePwd = "storepass";  
        final String foxclientKeyPwd = "keypass";  
        final String clientTrustKeyStoreFile = appBase + "/config/jmxkey/clienttrust.keystore";  
        final String clientTrustKeyStorePwd = "truststorepass";  
  
        // 创建SSLSocketFactory
        KeyStore clientKeyStore = KeyStore.getInstance("JKS");  
        clientKeyStore.load(new FileInputStream(clientKeyStoreFile), clientKeyStorePwd.toCharArray());  
       
        KeyStore clientTrustKeyStore = KeyStore.getInstance("JKS");  
        clientTrustKeyStore.load(new FileInputStream(clientTrustKeyStoreFile), clientTrustKeyStorePwd.toCharArray());  
  
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());  
        kmf.init(clientKeyStore, foxclientKeyPwd.toCharArray());  
  
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());  
        tmf.init(clientTrustKeyStore);  
  
        SSLContext sslContext = SSLContext.getInstance("TLSv1");  
        sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);  
        SSLSocketFactory ssf = sslContext.getSocketFactory();
        
        // 创建JMX客户端
        HashMap<String, Object> env = new HashMap<>();
        env.put("jmx.remote.profiles", "TLS");
        env.put("jmx.remote.tls.socket.factory", ssf);
        env.put("jmx.remote.tls.enabled.protocols", "TLSv1");
        env.put("jmx.remote.tls.enabled.cipher.suites",
                "SSL_RSA_WITH_3DES_EDE_CBC_SHA");

        JMXServiceURL url = new JMXServiceURL(protocol, host, port);
        JMXConnector jmxc = JMXConnectorFactory.connect(url, env);
        MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
        
        // 获取所有的域
        final String domains[] = mbsc.getDomains();
        for (int i = 0; i < domains.length; i++)
        {
            System.out.println("Domain[" + i + "] = " + domains[i]);
        }
        
        // 调用方法
        final String domain = "app";
        final String className = AppInfo.class.getName();
        final String name = domain + ":" + "name=" + className;
        final ObjectName objectName = ObjectName.getInstance(name);
        AppInfoMXBean appInfo = JMX.newMBeanProxy(
                mbsc, objectName, AppInfoMXBean.class);
        System.out.println(appInfo.getAppName());
        System.out.println(appInfo.getAppVersion());

        jmxc.close();


keystore和trustkeystore生成

# 生成服务端keystore
keytool -genkey -alias server -keyalg rsa -keysize 1024 -sigalg sha256withrsa -keypass keypass -keystore E:\app\config\jmxkey\server.keystore -storepass storepass

# 生成客户端keystone
keytool -genkey -alias client -keyalg rsa -keysize 1024 -sigalg sha256withrsa -keypass keypass -keystore E:\app\config\jmxkey\client.keystore -storepass storepass

# 导出服务端证书
keytool -export -alias server -keystore E:\app\config\jmxkey\server.keystore -storepass storepass -file E:\app\config\jmxkey\server.cer

# 导出客户端证书
keytool -export -alias client -keystore E:\app\config\jmxkey\client.keystore -storepass storepass -file E:\app\config\jmxkey\client.cer

# 创建服务端truststore并导入客户端证书
keytool -import -alias client -keystore E:\app\config\jmxkey\servertrust.keystore -storepass truststorepass -file E:\app\config\jmxkey\client.cer

# 创建客户端truststore并导入服务端证书
keytool -import -alias server -keystore E:\app\config\jmxkey\clienttrust.keystore -storepass truststorepass -file E:\app\config\jmxkey\server.cer


参考文献:

《jmx rmi 穿越防火墙问题及jmxmp的替代方案》

http://blog.csdn.net/yangyan19870319/article/details/7244403


《11.4.3 TLS Socket Factory》

http://docs.oracle.com/cd/E19698-01/816-7609/6mdjrf86r/index.html


《Java-JSSE-SSL/TLS编程代码实例-双向认证》

http://blog.csdn.net/fw0124/article/details/41013333