在实际生产环境下,使用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
本文出自 “自强不息,厚德载物” 博客,谢绝转载!