[英]How to set JMX remote port system environment parameters through java code for remote monitoring?
我有一個程序,它需要動態(即在運行時)打開一個可用的套接字並在其上啟動一個JMX代理。 此JMX參數在Java代碼中設置,而不是通過命令行設置。 這很好用。 此后,需要遠程通過Java Visual VM監視(即發出JMX命令等)
該程序中的RMI服務器代理處於以下所述的開箱即用管理行為: http : //download.oracle.com/javase/6/docs/technotes/guides/management/agent.html
我的問題可以概括為:如何通過Java代碼將這些命令行屬性設置為系統級別,以便可以使用遠程分析?
-Dcom.sun.management.jmxremote.port=1234
如果通過命令行設置“jmxremote.port”和其他參數,則遠程監視工作正常。 我試圖通過Java而不是通過命令行找到一種方法。
程序無法通過命令行指定端口,因為必須在運行時計算出新的可用端口。
該過程需要遠程監控,並且在本地工作正常。 如果未在命令行中指定以下參數,則Java Visual VM不會連接到該進程。
-Dcom.sun.management.jmxremote.port=1234
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Djava.rmi.server.hostname=10.0.0.128
我試過了。
System.setProperty("com.sun.management.jmxremote.port",Integer.toString(port));
這是在啟動JMXConnectorServer之前在程序中完成的第一件事。 不幸的是,它沒有被認可。 只有運行時屬性(即通過命令行指定由Java Visual VM識別JMX連接)。
還遇到了可以從java集合類中提取屬性的方法但無法到達如何跟蹤屬性“com.sun.management.jmxremote.port =”
public static void setEnv(Map<String, String> newenv) throws Exception {
Class[] classes = Collections.class.getDeclaredClasses();
Map<String, String> env = System.getenv();
for(Class cl : classes) {
if("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
Field field = cl.getDeclaredField("m");
field.setAccessible(true);
Object obj = field.get(env);
Map<String, String> map = (Map<String, String>) obj;
//map.clear();
map.putAll(newenv);
}
}
}
任何幫助,將不勝感激!
kbec的答案顯示了方式,但對我沒有用 - 但是通過查看這篇文章,我能夠修改它並獲得一個有效的解決方案。
public static String loadJMXAgent(int port) throws IOException,
AttachNotSupportedException, AgentLoadException,
AgentInitializationException {
String name = ManagementFactory.getRuntimeMXBean().getName();
VirtualMachine vm = VirtualMachine.attach(name.substring(0,
name.indexOf('@')));
String lca = vm.getAgentProperties().getProperty(
"com.sun.management.jmxremote.localConnectorAddress");
if (lca == null) {
Path p = Paths.get(System.getProperty("java.home")).normalize();
if (!"jre".equals(p.getName(p.getNameCount() - 1).toString()
.toLowerCase())) {
p = p.resolve("jre");
}
File f = p.resolve("lib").resolve("management-agent.jar").toFile();
if (!f.exists()) {
throw new IOException("Management agent not found");
}
String options = String.format("com.sun.management.jmxremote.port=%d, " +
"com.sun.management.jmxremote.authenticate=false, " +
"com.sun.management.jmxremote.ssl=false", port);
vm.loadAgent(f.getCanonicalPath(), options);
lca = vm.getAgentProperties().getProperty(
"com.sun.management.jmxremote.localConnectorAddress");
}
vm.detach();
return lca;
}
這在Eclipse中可行,但是在命令行中使用它是另一回事 - 這里有一些討論為什么在Linux上使用Java Attach API會失敗? (即使maven構建完成)但我發現在我的類路徑中添加$ JAVA_HOME / lib / tools.jar解決了這個問題。
你會以一種錯誤的方式解決這個問題。 當您的代碼被調用時,您錯過了這些屬性產生任何影響的機會。
您需要創建一個RmiRegistry,然后創建一個鏈接到平台MBeanServer的JMXConnectorServer,如下所示:
private void createJmxConnectorServer() throws IOException {
LocateRegistry.createRegistry(1234);
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://localhost/jndi/rmi://localhost:1234/jmxrmi");
JMXConnectorServer svr = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
svr.start();
}
如果未將任何jmxremote
env指定為運行參數,則不會加載JMX管理代理程序。 你可以嘗試這個動態加載:
public static String loadJMXAgent(int port) throws IOException, AttachNotSupportedException, AgentLoadException, AgentInitializationException {
System.setProperty("com.sun.management.jmxremote.port", Integer.toString(port));
String name = ManagementFactory.getRuntimeMXBean().getName();
VirtualMachine vm = VirtualMachine.attach(name.substring(0, name.indexOf('@')));
String lca = vm.getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress");
if (lca == null) {
Path p = Paths.get(System.getProperty("java.home")).normalize();
if (!"jre".equals(p.getName(p.getNameCount()-1).toString().toLowerCase())) p = p.resolve("jre");
File f = p.resolve("lib").resolve("management-agent.jar").toFile();
if (!f.exists()) throw new IOException("Management agent not found");
vm.loadAgent(f.getCanonicalPath(), "com.sun.management.jmxremote");
lca = vm.getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress");
}
vm.detach();
return lca;
}
您必須包含jdk/lib/tools.jar
我嘗試了一些方法來指定java代碼中的jmxremote端口以在特定端口上建立連接,並且已經找到以下內容:
如果指定了jmxremote arg:在我的代碼修改必要的jmxremote System.properties之前, 平台mbean服務器由JVM啟動。 每個mbean服務器都有一個自己的bean注冊表。 平台和JVM mbeans無法以其他方式向其注冊自己的bean。
設置jmx端口屬性后,可以創建備用mbean服務器。 那將監聽你指定的正確的jmx端口。
這樣您就可以選擇平台服務器:
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
這樣你自己的 :
System.setProperty("com.sun.management.jmxremote.port","9991");
//...
MBeanServer mbsCustom=MBeanServerFactory.createMBeanServer();
還要考慮linux有它的loopback接口,所以你應該明確指定正確的主機名來監聽。
根據手冊, 不建議使用除平台之外的其他MBeanServer,但我可以想象一些命令行選項不是啟動服務器的方式。
這對我有用。 參考Oracle JMX教程 。 我假設您已經知道如何在下面的示例中使用SimpleMXBean。
package sample;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.rmi.registry.LocateRegistry;
import java.util.HashMap;
import java.util.Map;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
public class MBServerTest {
public static void loadJMXAgent(int port, MBeanServer mbs) throws IOException {
LocateRegistry.createRegistry(port);
System.out.println("Initialize the environment map");
Map<String,Object> env = new HashMap<String,Object>();
env.put("com.sun.management.jmxremote.authenticate", "false");
env.put("com.sun.management.jmxremote.ssl", "false");
System.out.println("Create an RMI connector server");
JMXServiceURL url =
new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:"+port+"/jmxrmi");
JMXConnectorServer cs =
JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
// Start the RMI connector server.
//
System.out.println("Start the RMI connector server");
cs.start();
}
public static void main(String[] args) throws Exception {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
loadJMXAgent(1199,mbs);
SimpleStandard cache = new SimpleStandard();
ObjectName name = new ObjectName(
"org.javalobby.tnt.jmx:type=ApplicationCacheMBean");
mbs.registerMBean(cache, name);
imitateActivity(cache);
}
private static void imitateActivity(SimpleStandard cache) {
while (true) {
try {
cache.cacheObject("hello");
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
}
System.setProperty()
與-D
命令行選項相同。 但是顯然你必須盡早調用它,以便在讀取之前設置屬性。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.