2011-09-01 16 views
8

Ho un programma che richiede dinamicamente (cioè in fase di esecuzione) l'apertura di un socket disponibile e l'avvio di un agente JMX. Questi parametri JMX vengono impostati all'interno del codice Java e non tramite la riga di comando. Funziona bene Successivamente è necessario per monitorare (cioè inviare comandi JMX ecc) attraverso Java visiva VM remotoCome impostare i parametri di ambiente del sistema di porte remote JMX tramite codice java per il monitoraggio remoto?

L'agente server RMI nel programma è sulle linee di fuori della gestione scatola descritte in: http://download.oracle.com/javase/6/docs/technotes/guides/management/agent.html

La domanda Posso essere riassunto come: Come è possibile impostare tali proprietà della riga di comando sul livello di sistema tramite il codice Java, in modo che sia possibile utilizzare il profilo remoto ??

-Dcom.sun.management.jmxremote.port=1234 

Se "jmxremote.port" e altri parametri vengono impostati attraverso la linea di comando, monitoraggio remoto funziona bene. Sto cercando di trovare un modo per farlo attraverso Java e non tramite la riga di comando.

Il programma non può specificare la porta tramite la riga di comando poiché la nuova porta disponibile deve essere calcolata in fase di esecuzione.

Il processo richiede il monitoraggio remoto e funziona a livello locale. Se i parametri seguenti non sono specificati alla riga di comando, Java Visual VM non si connette al processo.

-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 

Ho provato.

System.setProperty("com.sun.management.jmxremote.port",Integer.toString(port)); 

Questa è una delle prime cose fatte nel programma prima di avviare il JMXConnectorServer. Sfortunatamente non è riconosciuto. Solo le proprietà del tempo di esecuzione (ad esempio specificate tramite la riga di comando sono riconosciute per la connessione JMX da Java Visual VM).

è venuto anche attraverso le proprietà modo in cui può essere estratto da classi di insiemi java, ma non ha potuto raggiungere come rintracciare la proprietà "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); 
    } 
    } 
} 

Qualsiasi aiuto sarebbe apprezzato !

+0

Si dovrebbe modificare la tua domanda originale e includere gli esempi di codice che avete state postando nei commenti. – Perception

risposta

0

System.setProperty() è identico all'opzione della riga di comando -D. Tuttavia, ovviamente, è necessario chiamarlo abbastanza presto da impostare la proprietà prima che venga letto.

+0

La proprietà che viene letta dal profiler per il profiling remoto sono le proprietà predefinite impostate al momento dell'avvio di JVM. In questo caso quando inizia il codice java. Sto avviando il java visual vm profiler molto più tardi e impostando la proprietà prima che JMXConnectorServer sia avviato. Cercando di capire come superare la proprietà in modo che venga riflessa come un livello di sistema jmx e possa essere rilevata da java visual vm ?? Gradirei qualche suggerimento su come chiamarlo "abbastanza presto". – Devesh

+0

L'esecuzione dell'app senza '-Dcom.sun.management.jmxremote' e l'impostazione di questo env in runtime successivamente è una cattiva idea perché l'agente JMX non è stato caricato, quindi non può essere utilizzato. – kbec

2

Se non si specifica alcun valore jmxremote come parametro di esecuzione, l'agente di gestione JMX non è stato caricato. Si può provare questo per il caricamento dinamico:

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; 
} 

è necessario includere jdk/lib/tools.jar

9

risposta di kbec ha mostrato la via, ma non ha funzionato per me - tuttavia, cercando in this post sono stato in grado di modificare e ottenere un lavoro soluzione.

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; 
} 

Questo funziona in Eclipse però a farla funzionare nella riga di comando è una questione diversa - c'è qualche discussione su questo qui Why does using the Java Attach API fail on linux? (even though maven build completes) ma ho trovato l'aggiunta di $ JAVA_HOME/lib/strumenti.jar al mio classpath ha risolto il problema.

1

ho cercato alcuni modi per specificare la porta jmxremote dal codice Java di avere una connessione su una porta specifica e hanno capito quanto segue:

In caso jmxremote arg è specificato: Il server mbean piattaforma è avviato da JVM, prima che il mio codice modifichi il jmxremote System.properties necessario. Ogni server mbean ha un proprio registro di bean. I mofee di plaform e JVM non potevano registrare i propri bean su di esso in un altro modo.

È possibile creare un server mbean alternativo dopo aver impostato le proprietà della porta jmx. Che ascolterà sulla porta jmx corretta, hai specificato.

In questo modo si sceglie il server della piattaforma:

MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); 

In questo modo il proprio:

System.setProperty("com.sun.management.jmxremote.port","9991"); 
//... 
MBeanServer mbsCustom=MBeanServerFactory.createMBeanServer(); 

considerare anche che Linux ha la sua interfaccia di loopback così si dovrebbe specificare il nome host corretto esplicitamente per ascoltare.

Questo è non consigliato per utilizzare un altro MBeanServer rispetto alla piattaforma, in base ai manuali, ma posso immaginare alcune situazioni in cui le opzioni della riga di comando non sono il modo in cui è possibile avviare un server.

0

Questo è ciò che funziona per me. Riferimento Oracle JMX Tutorial. Suppongo che tu sappia già come utilizzare SimpleMXBean nel seguente esempio.

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) { 
      } 
     } 
    } 
} 
+0

Cura di spiegare il voto negativo? –

4

Stai andando in questo modo leggermente sbagliato. Nel momento in cui viene chiamato il tuo codice hai perso la possibilità che queste proprietà abbiano alcun effetto.

È necessario creare un rmiregistry e quindi creare un JMXConnectorServer legato alla piattaforma MBeanServer in questo modo:

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(); 
} 
Problemi correlati