JMX provides a standard way to instrument the Java runtime environment and applications, and the JMX Remote API allows that instrumentation to be accessed remotely. there are couple system properties that you need to setup.
To enable the JMX agent and configure its operation using jconsole
, your must set some specific system properties when you start the JVM. For local access, set the property com.sun.management.jmxremote
as follows when starting the JVM:
prompt> java -Dcom.sun.management.jmxremote AppName
And, to enable monitoring and management from remote systems [here we disable the authentication and ssl] , set the property:
-Dcom.sun.management.jmxremote.port=portNumber
-Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false
When we talk about the firewall settings, here is one quick question, Is the PortNumber pretty much all we needed to put it into our exception list? if you answer yes like me. you need read the following parts. or maybe that’s why you are redirected to this blog.
lets do a simple test, Just open you notepad and write a helloworld Application.
public class MyApp |
then Compile and Run the application.
C:\temp>javac MyApp.java C:\temp>java -cp "." -Dcom.sun.management.jmxremote.port=2222 -Dcom.sun.management.jmxremote.ssl=false |
Keep the application running, and Open Jconsole, put localost:2222 to the remote process field, and click to go. nothing special here, you will be able to see the Mbeans .
So, How does the jconsole communicate with our JMXRemote Port? your may run netstat or download a utility offered from microsoft called tcpview. when you filter to jconsole process, you may find the following sessions. besides, the port 2222, it open one extra tcp port . the port number looks like it just pick it up randomly
at the end of one day, if somebody enforce the firewall policy by adding port 2222 to the only allowed port, then Nobody can use the jconsole to monitor this jvm.
So how can we Restrict the JMX listening Port/TCP to use the predefined Port? here is the steps.
basic Idea, when the application startup, just start one JMXConnectorServer service explicitly. the server will expose jmxjmi service to the client. In java, there is one serverfactory called JMXConnectorServerFactory
public static JMXConnectorServer newJMXConnectorServer(JMXServiceURL serviceURL, Map<String,?> environment, MBeanServer mbeanServer) throws IOException
The connector server will generate an RMIServerImpl
based on the protocol (rmi
or iiop
) and, for rmi
, the port
if any. When the connector server is started, it will derive a stub from this object using its toStub
method and store the object using the given jndi-name
. The properties defined by the JNDI API are consulted as usual.
For example, if the JMXServiceURL
is:
service:jmx:rmi://ignoredhost/jndi/rmi://myhost/myname
then the connector server will generate an RMIJRMPServerImpl
and store its stub using the JNDI name
rmi://myhost/myname
then we just change the myapp.java to loadup the connecterserver directly.
finally code:
import java.lang.management.ManagementFactory; public class MyApp System.out.println("hello,world, press to continue"); int i=System.in.read(); |
Recompile and restart the app, run jconsole. check the tcp session. Only TCP Port 3333 is open and required this time now.
In this case, we owned the source code of our application. if you are using the commercial package or third party application, you can’t change their source code then.
not a big problem, the Insturment package allow Java programming language agents to instrument programs running on the JVM. we just inject the save logic by writing a customeragent , and use the javaagent parameter to load our customeAgent.
we define another class, named JconsoleAgent
import java.lang.instrument.Instrumentation; |
then export the compiled class to a jar file named Jconsoleagent.jar . Edit the MANIFEST.MF file inclued in the jar, and put one more line.
Manifest-Version: 1.0 |
then startup the application like
C:\temp>java -cp "." -DMyJMXPORT=3333 -javaagent:Jconsoleagent.jar MyApp
you will be able to use the port 3333 only here to do the jmx monitoring.
Hope it Helps.
Another question, if you have multi NICS on the server, you can specify which RMI server that will server the request by adding parameters like
-Djava.rmi.server.hostname=MyInternalNIC |
Also, make sure you jconsole client can resmove the MyInternalNIC to the same IPaddress as you defined on the server. otherwise, you can’t conenct to the remote server
here is my great reference link, http://www.cs.washington.edu/education/courses/cse341/98au/java/jdk1.2beta4/docs/guide/rmi/rmiNetworkingFAQ.html