wtorek, 19 sierpnia 2014

Using Spring to call jmx bean on JBoss7 / EAP 6

Recently I had to create a sample project showing how to call a JMX Bean exposed by one application by other one. It seems so easy... as usual. But with new JBoss 7 / EAP6 and their new remoting-jmx protocol I struggled a bit. So here how it should look like

There are many examples of JMX and Spring. But most of them use rmi for remote jmx calls. On JBoss 7 /EAP6 it's simply not possible. JBoss uses remoting-jmx protocol for jmx, and there are couple of things you should be aware before you use it.
  1. It's not standard, if you try to use it without proper config you will get MalformedUrlException: unknown protocol remoting-jmx exception.
  2. If you add proper jboss modules to your application, you still need to enable remote connections in standalone.xml

So, in my example I have 2 projects: jmx-test, and jmx-test-client.
Jmx-test contains IJmxTest interface, and it's implementation

public interface IJmxTest {

    int getValue();

    void setValue(int x);

}


@Component
@ManagedResource(objectName = "bean:name=testBean")
public class JmxTestBean implements IJmxTest {

    private int value;

    @ManagedAttribute
    public int getValue() {
        return value;
    }

    @ManagedAttribute
    public void setValue(final int x) {
        this.value = x;
    }
}



The bean is exposed as JmxBean with Spring

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:mbean-export />
    <context:mbean-server />
    <context:component-scan base-package="jmx" />

</beans>



That's simple. Now the tricky part, the client. From jmx-test I generate the client that contains the IJmxTest interface. I will use it to invoke the bean.

Here's the client spring config

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="clientConnector"
        class="org.springframework.jmx.support.MBeanServerConnectionFactoryBean">
        <property name="serviceUrl" value="service:jmx:remoting-jmx://myhost:9999" />
    </bean>
    <context:component-scan base-package="jmx" />


    <bean id="proxy" class="org.springframework.jmx.access.MBeanProxyFactoryBean">
        <property name="objectName" value="bean:name=testBean" />
        <property name="proxyInterface" value="jmx.IJmxTest" />
        <property name="server" ref="clientConnector" />
    </bean>

</beans>



Few important things:
  1.  the objectName property must match the objectName of Jmx bean you want to use
  2. proxyInterface is the name of the interface used by the Jmx bean
  3. server points to the connector of mbean server. If you don't specify it, it will assume local mbean server.
  4. Client connector - this is where all things happen. You must put valid remoting-jmx url here. Remember to set the proper hostname and port if you changed it.
  5. For the connection to work, ensure that remote connections to management inteface on port 9999 are allowed (this needs to be changed in standalone.xml, by default you can only connect with 'localhost')
Now you can autowire the jmx bean where you need it
@Component
public class JmxClientTest implements ApplicationListener<ContextRefreshedEvent> {
    @Autowired
    private IJmxTest jmxTest;
    @Override
    public void onApplicationEvent(final ContextRefreshedEvent event) {
        System.out.println(jmxTest.getValue());
        jmxTest.setValue(10);
        System.out.println(jmxTest.getValue());
    }
}



Remember to link your archives to additional modules with jboss-deployment-structure.xml file

<jboss-deployment-structure>
    <deployment>
        <dependencies>
            <module name="org.jboss.as.jmx" export="true" />
            <module name="org.jboss.remoting-jmx" services="import"/>
           </dependencies>
    </deployment>
</jboss-deployment-structure>



That's for EAP 6.2. If you're using EAP 6.0.0 use
<module name="org.jboss.remoting3.remoting-jmx" services="import" export="true"/>
Instead of

<module name="org.jboss.remoting-jmx" services="import"/> 

Brak komentarzy:

Prześlij komentarz