Search code examples
javajmxspring-jmx

Programmatically enabling remote jmx monitoring


I am attempting to enable my core java application for remote accessibility via JMX. However, two restrictions are making it harder than it should be.

a) I am not at the liberty to change the script which starts the app on the linux box. Therefore, I cannot pass any of the "jmxremote" parameters to the jvm.

b) It is very possible that the remote port ( com.sun.management.jmxremote.port = xxxx ) I specify is not open and I cannot modify the script to try another open port. I must do it automatically.

I tried to get around these restrictions by writing a class with would set all the required jmxremote params as well as find a "free" port.

public class JmxRemoteConnectionHelper{

    @Override
    public void init( ) throws Exception{

        InetAddress address = InetAddress.getLocalHost();
        String ipAddress    = address.getHostAddress();
        String hostname     = address.getHostName();
        String port         = String.valueOf( getFreePort( ) );

        System.setProperty("java.rmi.server.hostname", ipAddress );
        System.setProperty("com.sun.management.jmxremote", "true" );
        System.setProperty("com.sun.management.jmxremote.authenticate", "false" );
        System.setProperty("com.sun.management.jmxremote.ssl", "false" );
        System.setProperty("com.sun.management.jmxremote.port", port  );

    }

    private final int getFreePort( ){

        **//seedPort is passed in the constructor**
        int freePort            = seedPort;
        ServerSocket sSocket    = null;

        for( int i=ZERO; i<PORT_SCAN_COUNTER; i++ ){

            try{

                freePort        = freePort + i;
                sSocket         = new ServerSocket( freePort );

               //FOUND a free port.             
                break;

            }catch( Exception e ){
                //Log

            }finally{

                if( sSocket != null ){
                    try{
                            sSocket.close();
                        sSocket = null;
                    }catch(Exception e ){
                    //Log
                    }

                }
            }

        }

        return freePort;
    }

 }

As shown below, I, then initialize it via spring.

<bean id="JmxRemoteConnection" class="JmxRemoteConnectionHelper" init-method="init" />

<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean" depends-on="JmxRemoteConnection" />   

<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter" lazy-init="false" >
        <property name="assembler"      ref="assembler"/>
        <property name="namingStrategy" ref="namingStrategy"/>
        <property name="autodetect"     value="true"/>
        <property name="server"         ref="mbeanServer"/>
</bean>

<bean id="jmxAttributeSource" class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource"/>

<bean id="assembler" class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
        <property name="attributeSource" ref="jmxAttributeSource"/>
</bean>

<bean id="namingStrategy" class="org.springframework.jmx.export.naming.MetadataNamingStrategy" lazy-init="true">
        <property name="attributeSource" ref="jmxAttributeSource"/>
</bean>

To test, I start the app on my windows machine. It starts up correctly. However, when I bring up JConsole on the same box and try to connect via "remote process" (ip:port), I get a "connection refused" message at the bottom.

My suspicion is that the JMX agent is not seeing any of the remote system properties that I am setting.

I am using JDK 1.6.


Solution

  • Since you are already using Spring I think you should see if using a ConnectorServerFactoryBean can do what you are looking to do. I've never had to start a remote JMX server but it looks like that's what that object can do for you.