MINA(4)JMX with Spring
Using JMX with Spring Bean, here is my spring bean CaculateImpl, this may be my business logic bean.
package com.sillycat.easynio.plugins.jmx;
public class CaculateImpl implements CaculateInterface{
public int add(int x, int y) {
return x + y;
}
public String echo(String message) {
return "Hello, it is message from JMX = " + message;
}
public String securit() {
return "forbidden!";
}
}
There are 3 method in this bean, I only want to expose 2 of them.
The orignial interface for this business bean is
package com.sillycat.easynio.plugins.jmx;
public interface CaculateInterface {
public int add(int x, int y);
public String echo(String message);
public String securit();
}
The only interface I want to open to JMX.
package com.sillycat.easynio.plugins.jmx;
public interface CaculateJMXInterface {
public int add(int x, int y);
public String echo(String message);
}
The dependecies in pom.xml are as follow:
<dependency>
<groupId>mx4j</groupId>
<artifactId>mx4j</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>mx4j</groupId>
<artifactId>mx4j-tools</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
The JMX Spring Configuration file jmx-context.xml:
<bean id="caculate" class="com.sillycat.easynio.plugins.jmx.CaculateImpl">
</bean>
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="com.sillycat:caculate=CaculateJMX" value-ref="caculate" />
<entry key="mx4j:name=HttpAdaptor" value-ref="httpAdaptor" />
</map>
</property>
<property name="assembler" ref="assembler" />
</bean>
<bean id="assembler"
class="org.springframework.jmx.export.assembler.InterfaceBasedMBeanInfoAssembler">
<property name="managedInterfaces">
<list>
<value>com.sillycat.easynio.plugins.jmx.CaculateJMXInterface</value>
</list>
</property>
</bean>
<bean id="registry" class="org.springframework.remoting.rmi.RmiRegistryFactoryBean">
<property name="port">
<value>9875</value>
</property>
</bean>
<bean id="serverConnector" class="org.springframework.jmx.support.ConnectorServerFactoryBean">
<property name="objectName">
<value>connector:name=rmi</value>
</property>
<property name="serviceUrl">
<value>service:jmx:rmi://localhost/jndi/rmi://localhost:9875/jmxrmi</value>
</property>
</bean>
We can use the proxy client to manage the JMX bean, jmxclient-context.xml:
<bean id="caculateJMXClient" class="org.springframework.jmx.access.MBeanProxyFactoryBean">
<property name="connectOnStartup" value="true" />
<property name="objectName" value="com.sillycat:caculate=CaculateJMX" />
<property name="proxyInterface">
<value>com.sillycat.easynio.plugins.jmx.CaculateJMXInterface</value>
</property>
<property name="serviceUrl">
<value>service:jmx:rmi://localhost/jndi/rmi://localhost:9875/jmxrmi</value>
</property>
</bean>
We can call the JMX bean using this client class:
package com.sillycat.easynio.plugins.jmx;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "file:src/test/resources/test-context.xml" })
public class CaculateJMXClientTest {
@Autowired
@Qualifier("caculateJMXClient")
private CaculateJMXInterface caculateJMXClient;
@Test
public void dumy() {
Assert.assertTrue(true);
}
@Test
public void add() {
int sum = caculateJMXClient.add(100, 200);
Assert.assertEquals(sum, 300);
}
@Test
public void echo(){
System.out.println(caculateJMXClient.echo("sillycat"));
}
}
Easily, we can use a mx4j adaptor to make the end user to use browsers.
mx4j-context.xml:
<bean id="httpAdaptor" class="mx4j.tools.adaptor.http.HttpAdaptor">
<property name="processor">
<bean id="xsltProcessor" class="mx4j.tools.adaptor.http.XSLTProcessor"/>
</property>
<property name="host">
<value>localhost</value>
</property>
<property name="port">
<value>8000</value>
</property>
</bean>
We need using this kind of application to star the adaptor server, that is weird.
public class MX4JClientMain {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"main-context.xml");
HttpAdaptor httpAdaptor = (HttpAdaptor) ctx.getBean("httpAdaptor");
try {
httpAdaptor.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Then we can visit the URL as follow:
http://localhost:8000/serverbydomain
Filter: *:*
Filter: com.sillycat:*, click the Query button.
We can using the JMX bean now.
I change the spring startup listener to start the adaptor server instead of application:
package com.sillycat.easynio.plugins.jmx;
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import mx4j.tools.adaptor.http.HttpAdaptor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.WebApplicationContextUtils;
public class JMXContextLoadListener extends ContextLoaderListener implements
ServletContextListener {
private final Log log = LogFactory.getLog(getClass());
public void contextInitialized(ServletContextEvent event) {
super.contextInitialized(event);
ServletContext context = event.getServletContext();
setupContext(context);
}
protected void setupContext(final ServletContext context) {
ApplicationContext ctx = WebApplicationContextUtils
.getRequiredWebApplicationContext(context);
HttpAdaptor httpAdaptor = (HttpAdaptor) ctx.getBean("httpAdaptor");
try {
httpAdaptor.start();
} catch (IOException e) {
log.error(e);
}
}
}
<listener>
<listener-class>com.sillycat.easynio.plugins.jmx.JMXContextLoadListener</listener-class>
</listener>
references:
http://blog.youkuaiyun.com/shirdrn/article/details/6358688
http://topmanopensource.iteye.com/blog/832848
http://topmanopensource.iteye.com/blog/832851
http://topmanopensource.iteye.com/blog/832855
Using JMX with Spring Bean, here is my spring bean CaculateImpl, this may be my business logic bean.
package com.sillycat.easynio.plugins.jmx;
public class CaculateImpl implements CaculateInterface{
public int add(int x, int y) {
return x + y;
}
public String echo(String message) {
return "Hello, it is message from JMX = " + message;
}
public String securit() {
return "forbidden!";
}
}
There are 3 method in this bean, I only want to expose 2 of them.
The orignial interface for this business bean is
package com.sillycat.easynio.plugins.jmx;
public interface CaculateInterface {
public int add(int x, int y);
public String echo(String message);
public String securit();
}
The only interface I want to open to JMX.
package com.sillycat.easynio.plugins.jmx;
public interface CaculateJMXInterface {
public int add(int x, int y);
public String echo(String message);
}
The dependecies in pom.xml are as follow:
<dependency>
<groupId>mx4j</groupId>
<artifactId>mx4j</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>mx4j</groupId>
<artifactId>mx4j-tools</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
The JMX Spring Configuration file jmx-context.xml:
<bean id="caculate" class="com.sillycat.easynio.plugins.jmx.CaculateImpl">
</bean>
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="com.sillycat:caculate=CaculateJMX" value-ref="caculate" />
<entry key="mx4j:name=HttpAdaptor" value-ref="httpAdaptor" />
</map>
</property>
<property name="assembler" ref="assembler" />
</bean>
<bean id="assembler"
class="org.springframework.jmx.export.assembler.InterfaceBasedMBeanInfoAssembler">
<property name="managedInterfaces">
<list>
<value>com.sillycat.easynio.plugins.jmx.CaculateJMXInterface</value>
</list>
</property>
</bean>
<bean id="registry" class="org.springframework.remoting.rmi.RmiRegistryFactoryBean">
<property name="port">
<value>9875</value>
</property>
</bean>
<bean id="serverConnector" class="org.springframework.jmx.support.ConnectorServerFactoryBean">
<property name="objectName">
<value>connector:name=rmi</value>
</property>
<property name="serviceUrl">
<value>service:jmx:rmi://localhost/jndi/rmi://localhost:9875/jmxrmi</value>
</property>
</bean>
We can use the proxy client to manage the JMX bean, jmxclient-context.xml:
<bean id="caculateJMXClient" class="org.springframework.jmx.access.MBeanProxyFactoryBean">
<property name="connectOnStartup" value="true" />
<property name="objectName" value="com.sillycat:caculate=CaculateJMX" />
<property name="proxyInterface">
<value>com.sillycat.easynio.plugins.jmx.CaculateJMXInterface</value>
</property>
<property name="serviceUrl">
<value>service:jmx:rmi://localhost/jndi/rmi://localhost:9875/jmxrmi</value>
</property>
</bean>
We can call the JMX bean using this client class:
package com.sillycat.easynio.plugins.jmx;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "file:src/test/resources/test-context.xml" })
public class CaculateJMXClientTest {
@Autowired
@Qualifier("caculateJMXClient")
private CaculateJMXInterface caculateJMXClient;
@Test
public void dumy() {
Assert.assertTrue(true);
}
@Test
public void add() {
int sum = caculateJMXClient.add(100, 200);
Assert.assertEquals(sum, 300);
}
@Test
public void echo(){
System.out.println(caculateJMXClient.echo("sillycat"));
}
}
Easily, we can use a mx4j adaptor to make the end user to use browsers.
mx4j-context.xml:
<bean id="httpAdaptor" class="mx4j.tools.adaptor.http.HttpAdaptor">
<property name="processor">
<bean id="xsltProcessor" class="mx4j.tools.adaptor.http.XSLTProcessor"/>
</property>
<property name="host">
<value>localhost</value>
</property>
<property name="port">
<value>8000</value>
</property>
</bean>
We need using this kind of application to star the adaptor server, that is weird.
public class MX4JClientMain {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"main-context.xml");
HttpAdaptor httpAdaptor = (HttpAdaptor) ctx.getBean("httpAdaptor");
try {
httpAdaptor.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Then we can visit the URL as follow:
http://localhost:8000/serverbydomain
Filter: *:*
Filter: com.sillycat:*, click the Query button.
We can using the JMX bean now.
I change the spring startup listener to start the adaptor server instead of application:
package com.sillycat.easynio.plugins.jmx;
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import mx4j.tools.adaptor.http.HttpAdaptor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.WebApplicationContextUtils;
public class JMXContextLoadListener extends ContextLoaderListener implements
ServletContextListener {
private final Log log = LogFactory.getLog(getClass());
public void contextInitialized(ServletContextEvent event) {
super.contextInitialized(event);
ServletContext context = event.getServletContext();
setupContext(context);
}
protected void setupContext(final ServletContext context) {
ApplicationContext ctx = WebApplicationContextUtils
.getRequiredWebApplicationContext(context);
HttpAdaptor httpAdaptor = (HttpAdaptor) ctx.getBean("httpAdaptor");
try {
httpAdaptor.start();
} catch (IOException e) {
log.error(e);
}
}
}
<listener>
<listener-class>com.sillycat.easynio.plugins.jmx.JMXContextLoadListener</listener-class>
</listener>
references:
http://blog.youkuaiyun.com/shirdrn/article/details/6358688
http://topmanopensource.iteye.com/blog/832848
http://topmanopensource.iteye.com/blog/832851
http://topmanopensource.iteye.com/blog/832855