虽然似乎有一些关于如何通过各种防火墙和隧道方案公开JMX的文档,但我有点想要相反。我想确保JMX只能由本地机器访问。不幸的是,似乎“开箱即用”的管理选项不允许将端口限制为本地接口,netstat显示它们在任何/所有接口上进行侦听。
http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html#gdevf
我不得不承认我对JMX中的间接层,RMI注册表,连接器,适配器等感到困惑。
我想将其打开,然后通过SSH进行隧道传输,而不是将其暴露给世界,然后必须执行艰巨而多余的用户管理和安全配置。能够使用内置的RMI注册表而不必运行外部注册表会很好。
答案 0 :(得分:3)
如果您从本地主机访问,则可以执行JConsole和JVisualVM在这种情况下执行的操作,即使用Attach API查找服务器的本地地址(如果您获得的内容)使用-Dcom.sun.management.jmxremote但不是-Dcom.sun.management.jmxremote.port = N)运行并连接到它。在另一个答案中,Thraidh表示,即使在这种情况下,也可以打开一个可远程访问的端口,这在早期版本中是正确的,但在几年内并未如此。
Fredrik的解决方案有效,但有点矫枉过正。您只需要定义RMIServerSocketFactory,而不是RMISocketFactory(定义客户端和服务器)。这消除了专门配置客户端的需要。 http://vafer.org/blog/20061010091658的代码对我来说是正确的。
使用命令行属性(如-Dcom.sun.management.jmxremote)构建的“开箱即用”管理只能在您需要开始使用JMX API本身进行编程之前到目前为止。我们一般不愿意将开箱即用的管理演变成一个完整的并行API,这就是为什么像这样的问题无法实现的原因。我们将解释如何从一个here转到另一个。{/ p>
ÉamonnMcManus,JMX Spec Lead
答案 1 :(得分:2)
有点迟到的答案,但如果它对你(或其他人)来说仍然是一个问题,我认为这样做会有所帮助:
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.*;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.RMISocketFactory;
import javax.management.MBeanServer;
import javax.management.remote.*;
public class LocalJMXPort {
public static void main(String[] args) {
try {
int port = 12468;
// Create an instance of our own socket factory (see below)
RMISocketFactory factory = new LocalHostSocketFactory();
// Set it as default
RMISocketFactory.setSocketFactory(factory);
// Create our registry
LocateRegistry.createRegistry(port);
// Get the MBeanServer and setup a JMXConnectorServer
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://127.0.0.1:"+port+"/jndi/rmi://127.0.0.1:"+port+"/jmxrmi");
JMXConnectorServer rmiServer = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
rmiServer.start();
// Say something
System.out.println("Connect your jconsole to localhost:"+port+". Press a key to exit");
// Wait for a key press
int in = System.in.read();
//Exit
System.out.println("Exiting");
System.exit(0);
} catch(Exception ex) {
ex.printStackTrace();
}
}
static private class LocalHostSocketFactory extends RMISocketFactory {
public ServerSocket createServerSocket(int port) throws IOException {
ServerSocket ret = new ServerSocket();
ret.bind(new InetSocketAddress("localhost", port));
return ret;
}
public Socket createSocket(String host, int port) throws IOException {
return new Socket(host, port);
}
}
}
我只是把它放在一起,有可能我做了一些非常愚蠢的事情,因为我唯一的目标是让它绑定到localhost:port而不是*:port,这部分似乎有效。
如果有可能更好的事情或者只是简单的愚蠢,请随意评论。
答案 2 :(得分:1)
无法帮助太阳做这件事。即使jmx适配器开始使用jdk(我认为6)?我仍然使用mx4j进行最省力的适配器设置。在127.0.0.1或仅内部接口上启动mx4j http适配器是微不足道的。然后SOP是使用端口转发ssh in或使用带有wget命令的脚本。
答案 3 :(得分:1)
不幸的是,目前无法做到这一点。
根据Sun文档,唯一的-Dcom.sun.management.jmxremote应该只打开本地端口,而-Dcom.sun.management.jmxremote.port =打开一个可远程访问的端口。
两种方式都可以打开一个可以从远程访问的附加随机端口。
我见过-Dcom.sun.management.jmxremote.host =,但这似乎没有任何效果。
我得出的结论是没有办法使用本地防火墙屏蔽服务器。