Spring与JMX集成

Spring与JMX集成,实现方式灵活而且简单,主要体现在:

1、可以自动探测实现MBean接口的MBean对象,而且可以将一个普通的Spring Bean注册为MBean;

2、定制管理MBean的接口,根据需要暴露特定管理MBean的操作;

3、使用注解定义MBean管理接口;

4、可以实现对本地和远程MBean的代理。

标准MBean管理

对于实现标准MBean接口MBean资源,在Spring中可以设置不同的探测模式,主要是通过MBeanExporter来实现。例如,定义MBean管理接口:

[java] view plain copy
  1. packageorg.shirdrn.spring.jmx.autodetect;
  2. publicinterfaceMyObjectMBean{
  3. publiclonggetId();
  4. publicvoidsetId(longid);
  5. publicStringgetName();
  6. publicvoidsetName(Stringname);
  7. publicStringshow();
  8. }

对应的MBean实现,如下所示:

[java] view plain copy
  1. packageorg.shirdrn.spring.jmx.autodetect;
  2. importorg.apache.log4j.Logger;
  3. publicclassMyObjectimplementsMyObjectMBean{
  4. privatestaticfinalLoggerLOG=Logger.getLogger(MyObject.class);
  5. privatelongid;
  6. privateStringname;
  7. publicMyObject(){
  8. super();
  9. }
  10. publicMyObject(longid,Stringname){
  11. super();
  12. this.id=id;
  13. this.name=name;
  14. }
  15. publiclonggetId(){
  16. returnid;
  17. }
  18. publicvoidsetId(longid){
  19. this.id=id;
  20. }
  21. publicStringgetName(){
  22. returnname;
  23. }
  24. publicvoidsetName(Stringname){
  25. this.name=name;
  26. }
  27. publicStringshow(){
  28. StringBuffersb=newStringBuffer().append("id=").append(id).append(
  29. ",name=").append(name);
  30. LOG.info("show()="+sb.toString());
  31. returnsb.toString();
  32. }
  33. }

上面是一个标准MBean的实现,可以使用JavaSE 6平台的JMX服务来管理,但是在Spring集成的环境下,也可以重用这些MBean实现,例如下面是一个典型的配置:

[xhtml] view plain copy
  1. <?xmlversion="1.0"encoding="UTF-8"?>
  2. <beans
  3. xmlns="http://www.springframework.org/schema/beans"
  4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
  6. <beanid="mbServer"class="org.springframework.jmx.export.MBeanExporter">
  7. <propertyname="autodetectModeName">
  8. <value>AUTODETECT_ALL</value>
  9. </property>
  10. </bean>
  11. <beanname="mydomain:myobj=MyObjectMBean"class="org.shirdrn.spring.jmx.autodetect.MyObject">
  12. <propertyname="id">
  13. <value>90000000001</value>
  14. </property>
  15. <propertyname="name">
  16. <value>shirdrn</value>
  17. </property>
  18. </bean>
  19. </beans>

上面配置中,MBeanExporter会查找本地MBean Server,指定的探测模式autodetectModeName为AUTODETECT_ALL,这也是MBeanExporter的默认值(这个属性完全可以省略,不用配置),无需手动向MBean Server进行注册,便能管理配置的MBean对象“mydomain:myobj=MyObjectMBean”。

对于探测模式autodetectModeName属性,Spring提供了4个取值:

AUTODETECT_NONE 不启用自动探测,需要手动向MBean Server进行注册,即通过MBeanExporter的beans属性进入注册;

AUTODETECT_MBEAN 在当前IOC容器中进行查找MBean组件;

AUTODETECT_ASSEMBLER 设置根据MBeanInfoAssembler的策略进行探测;

AUTODETECT_ALL 自动探测,是AUTODETECT_MBEAN和AUTODETECT_ASSEMBLER的并集。

另外,Spring的MBeanExporter也提供了autodetect属性,取值为true和false,指定对MBean组件的探测行为。

普通Spring Bean管理

对于一个普通的Spring Bean,也可以作为MBean来进行管理,Spring可以很好地支持。如下面一个普通的Java类:

[java] view plain copy
  1. packageorg.shirdrn.spring.jmx;
  2. importorg.apache.log4j.Logger;
  3. publicclassMyJavaObject{
  4. privatestaticfinalLoggerLOG=Logger.getLogger(MyJavaObject.class);
  5. privatelongid;
  6. privateStringname;
  7. publicMyJavaObject(){
  8. super();
  9. }
  10. publicMyJavaObject(longid,Stringname){
  11. super();
  12. this.id=id;
  13. this.name=name;
  14. }
  15. publiclonggetId(){
  16. returnid;
  17. }
  18. publicvoidsetId(longid){
  19. this.id=id;
  20. }
  21. publicStringgetName(){
  22. returnname;
  23. }
  24. publicvoidsetName(Stringname){
  25. this.name=name;
  26. }
  27. publicStringshow(){
  28. StringBuffersb=newStringBuffer().append("id=").append(id).append(
  29. ",name=").append(name);
  30. LOG.info("show()="+sb.toString());
  31. returnsb.toString();
  32. }
  33. }

它并没有实现MBean管理接口,可以通过MBeanExporter的beans属性进行注册,配置如下所示:

[java] view plain copy
  1. <?xmlversion="1.0"encoding="UTF-8"?>
  2. <beans
  3. xmlns="http://www.springframework.org/schema/beans"
  4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
  6. <beanid="mbServer"class="org.springframework.jmx.export.MBeanExporter">
  7. <propertyname="beans">
  8. <map>
  9. <entrykey="mydomain:myjavaobj=MyJavaObject"value-ref="myobj"/>
  10. </map>
  11. </property>
  12. </bean>
  13. <beanname="myobj"class="org.shirdrn.spring.jmx.MyJavaObject">
  14. <propertyname="id">
  15. <value>90000000001</value>
  16. </property>
  17. <propertyname="name">
  18. <value>shirdrn</value>
  19. </property>
  20. </bean>
  21. </beans>

因为org.shirdrn.spring.jmx.MyJavaObject没有对应的MBean接口,所以默认情况下,该类中public的成员都会暴露出来,通过MBeanServer可以管理。实际上,系统中MBean的某些属性或方法可能不需要暴露给外部进行管理,为了克服这种缺点,Spring提供了基于方法列表和接口定制的功能,可以将你所感兴趣的属性或方法暴露给外部管理。

基于方法列表和接口定制的MBean管理

对于上述普通的Java类MyJavaObject,可以通过定制接口和方法列表,来暴露MBean属性或方法。例如,一个方法列表,可以在进行配置的时候指定,如下所示:

[xhtml] view plain copy
  1. <beanid="assembler"class="org.springframework.jmx.export.assembler.MethodNameBasedMBeanInfoAssembler">
  2. <propertyname="managedMethods"value="setId,setName,show"/>
  3. </bean>

上面通过org.springframework.jmx.export.assembler.MethodNameBasedMBeanInfoAssembler来进行方法列表的设置。而对于接口,可以定义一个接口,如下所示:

[java] view plain copy
  1. packageorg.shirdrn.spring.jmx.selected.interfaces;
  2. publicinterfaceSelectedMethodsInterface{
  3. publiclongsetId(longid);
  4. publicvoidsetName(Stringname);
  5. publicvoidshow();
  6. }

Spring配置,如下所示:

[xhtml] view plain copy
  1. <beanid="assembler"class="org.springframework.jmx.export.assembler.InterfaceBasedMBeanInfoAssembler">
  2. <propertyname="managedInterfaces">
  3. <list>
  4. <value>org.shirdrn.spring.jmx.selected.interfaces.SelectedMethodsInterface</value>
  5. </list>
  6. </property>
  7. </bean>

上面通过org.springframework.jmx.export.assembler.InterfaceBasedMBeanInfoAssembler,可以设置一个接口列表,来管理MBean暴露的接口。

对于上面两种方式,都得到一个assembler实例,需要将其注入到org.springframework.jmx.export.MBeanExporter中,如下所示:

[xhtml] view plain copy
  1. <beanid="exporter"class="org.springframework.jmx.export.MBeanExporter">
  2. <propertyname="beans">
  3. <map>
  4. <entrykey="mydomain:javaObj=MyJavaObject"value-ref="javaObject"/>
  5. </map>
  6. </property>
  7. <propertyname="assembler"ref="assembler"/>
  8. </bean>

基于注解的MBean管理

对于一个普通的Java类,作为MBean需要被管理,可以通过注解指定要暴露的属性和方法,示例如下:

[java] view plain copy
  1. packageorg.shirdrn.spring.jmx.annotation;
  2. importorg.apache.log4j.Logger;
  3. importorg.springframework.jmx.export.annotation.ManagedAttribute;
  4. importorg.springframework.jmx.export.annotation.ManagedOperation;
  5. importorg.springframework.jmx.export.annotation.ManagedResource;
  6. @ManagedResource(objectName="annojmx:myjao=AnnotationObject",description="MyJavaAnnotationObject")
  7. publicclassMyJavaAnnotationObject{
  8. privatestaticfinalLoggerLOG=Logger.getLogger(MyJavaAnnotationObject.class);
  9. privatelongid;
  10. privateStringname;
  11. publicMyJavaAnnotationObject(){
  12. super();
  13. }
  14. publicMyJavaAnnotationObject(longid,Stringname){
  15. super();
  16. this.id=id;
  17. this.name=name;
  18. }
  19. @ManagedAttribute
  20. publiclonggetId(){
  21. returnid;
  22. }
  23. publicvoidsetId(longid){
  24. this.id=id;
  25. }
  26. publicStringgetName(){
  27. returnname;
  28. }
  29. @ManagedAttribute
  30. publicvoidsetName(Stringname){
  31. this.name=name;
  32. }
  33. @ManagedOperation
  34. publicStringshow(){
  35. StringBuffersb=newStringBuffer().append("id=").append(id).append(
  36. ",name=").append(name);
  37. LOG.info("show()="+sb.toString());
  38. returnsb.toString();
  39. }
  40. }

上面@ManagedResource表示指定该类的实例作为MBean注册到MBean Server中,然后可以通过对属性和方法分别使用@ManagedAttribute和@ManagedOperation来指定暴露的属性和方法。有关这些注解的详细内容,可以查阅相关文档。

下面是一个基本的配置内容:

[xhtml] view plain copy
  1. <?xmlversion="1.0"encoding="UTF-8"?>
  2. <beansxmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
  5. <beanid="exporter"class="org.springframework.jmx.export.MBeanExporter">
  6. <propertyname="assembler"ref="assembler"/>
  7. <propertyname="namingStrategy"ref="namingStrategy"/>
  8. </bean>
  9. <beanid="assembler"
  10. class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
  11. <propertyname="attributeSource"ref="jmxas"/>
  12. </bean>
  13. <beanid="namingStrategy"
  14. class="org.springframework.jmx.export.naming.MetadataNamingStrategy">
  15. <propertyname="attributeSource"ref="jmxas"/>
  16. </bean>
  17. <beanid="jmxas"class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource"/>
  18. <beanid="javaObj"
  19. class="org.shirdrn.spring.jmx.annotation.MyJavaAnnotationObject">
  20. <propertyname="id"value="201122121200"/>
  21. <propertyname="name"value="shirdrn"/>
  22. </bean>
  23. </beans>

上面使用了Spring的MBeanExporter,可以看到,Spring配置内容相对较多。

Spring还提供两种简化配置的方式,

一种是,提供了org.springframework.jmx.export.annotation.AnnotationMBeanExporter,可以将上述配置大大简化,等价的配置如下所示:

[xhtml] view plain copy
  1. <?xmlversion="1.0"encoding="UTF-8"?>
  2. <beansxmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
  5. <beanclass="org.springframework.jmx.export.annotation.AnnotationMBeanExporter"/>
  6. <beanname="myAnnoObject"
  7. class="org.shirdrn.spring.jmx.annotation.MyJavaAnnotationObject">
  8. <propertyname="id"value="201122121200"/>
  9. <propertyname="name"value="shirdrn"/>
  10. </bean>
  11. </beans>

另一种是,提供了<context:mbean-export />标签,更加简洁,等价的配置如下所示:

[xhtml] view plain copy
  1. <?xmlversion="1.0"encoding="UTF-8"?>
  2. <beansxmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
  6. http://www.springframework.org/schema/context
  7. http://www.springframework.org/schema/context/spring-context-2.5.xsd">
  8. <context:mbean-exportregistration="failOnExisting"/>
  9. <beanname="myAnnoObject"
  10. class="org.shirdrn.spring.jmx.annotation.MyJavaAnnotationObject">
  11. <propertyname="id"value="201122121200"/>
  12. <propertyname="name"value="shirdrn"/>
  13. </bean>
  14. </beans>

通过远程代理访问MBean

根据JavaSE 6平台的JMX技术架构定义,分为设备层、代理层、远程管理层这三层,我们通过可以使用Spring提供的org.springframework.jmx.access.MBeanProxyFactoryBean实现,定义代理,来访问MBean Server管理MBean资源。实际上,Spring提供的这个代理功能位于JMX架构的远程管理层,那么在代理层和远程管理层之间,要定义连接器,才能通过远程管理层访问到代理层的MBean Server组件。下面通过实例来实现:

首先,定义个普通的Java类,作为待管理的MBean,如下所示:

[java] view plain copy
  1. packageorg.shirdrn.spring.jmx.rmi;
  2. importorg.apache.log4j.Logger;
  3. publicclassMyJavaObject{
  4. privatestaticfinalLoggerLOG=Logger.getLogger(MyJavaObject.class);
  5. privatelongid;
  6. privateStringname;
  7. publicMyJavaObject(){
  8. super();
  9. }
  10. publicMyJavaObject(longid,Stringname){
  11. super();
  12. this.id=id;
  13. this.name=name;
  14. }
  15. publiclonggetId(){
  16. returnid;
  17. }
  18. publicvoidsetId(longid){
  19. this.id=id;
  20. }
  21. publicStringgetName(){
  22. returnname;
  23. }
  24. publicvoidsetName(Stringname){
  25. this.name=name;
  26. }
  27. publicStringshow(){
  28. StringBuffersb=newStringBuffer().append("id=").append(id).append(
  29. ",name=").append(name);
  30. LOG.info("show()="+sb.toString());
  31. returnsb.toString();
  32. }
  33. }

其次,定义了一个Java接口,来按需暴露操作MBean资源的方法:

[java] view plain copy
  1. packageorg.shirdrn.spring.jmx.rmi;
  2. publicinterfaceMyManagedInterfaces{
  3. publiclongsetId(longid);
  4. publicStringgetName();
  5. publicStringshow();
  6. }

再次,看一下我们模拟代理层Spring配置server.xml内容:

[xhtml] view plain copy
  1. <?xmlversion="1.0"encoding="UTF-8"?>
  2. <beansxmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
  5. <beanid="exporter"class="org.springframework.jmx.export.MBeanExporter">
  6. <propertyname="beans">
  7. <map>
  8. <entrykey="mydomain:myjavaobj=MyJavaObject"value-ref="myJavaObj"/>
  9. </map>
  10. </property>
  11. <propertyname="assembler"ref="assembler"/>
  12. </bean>
  13. <beanid="assembler"
  14. class="org.springframework.jmx.export.assembler.InterfaceBasedMBeanInfoAssembler">
  15. <propertyname="managedInterfaces">
  16. <list>
  17. <value>org.shirdrn.spring.jmx.rmi.MyManagedInterfaces</value>
  18. </list>
  19. </property>
  20. </bean>
  21. <beanname="myJavaObj"class="org.shirdrn.spring.jmx.rmi.MyJavaObject">
  22. <propertyname="id"value="88000000001"/>
  23. <propertyname="name"value="shirdrn"/>
  24. </bean>
  25. <beanid="server"class="org.springframework.jmx.support.ConnectorServerFactoryBean"depends-on="registry">
  26. <propertyname="objectName">
  27. <value>connector:name=rmi</value>
  28. </property>
  29. <propertyname="serviceUrl">
  30. <value>service:jmx:rmi://localhost/jndi/rmi://localhost:1099/jmxrmi</value>
  31. </property>
  32. </bean>
  33. <beanid="registry"class="org.springframework.remoting.rmi.RmiRegistryFactoryBean">
  34. <propertyname="port">
  35. <value>1099</value>
  36. </property>
  37. </bean>
  38. </beans>

上半部分配置已经非常熟悉,就是将MBean注册到MBean Server中。下半部分是有关连接器的配置,它是基于RMI协议来进行适配,通过Spring提供的org.springframework.jmx.support.ConnectorServerFactoryBean来实现器,这样,远程管理层可以连接到启动的连接服务器,来访问MBean资源。

然后,我们启动MBean Server及其连接服务器,代码如下所示:

[java] view plain copy
  1. packageorg.shirdrn.spring.jmx.rmi;
  2. importorg.apache.log4j.Logger;
  3. importorg.springframework.context.support.ClassPathXmlApplicationContext;
  4. publicclassServer{
  5. privatestaticfinalLoggerLOG=Logger.getLogger(Server.class);
  6. publicstaticvoidmain(String[]args)throwsException{
  7. newClassPathXmlApplicationContext("org/shirdrn/spring/jmx/rmi/server.xml");
  8. LOG.info("Serverstarted.");
  9. Objectlock=newObject();
  10. synchronized(lock){
  11. lock.wait();
  12. }
  13. }
  14. }

启动后,我们定义的MBean已经注册到本地MBean Server中,同时启动了连接器,监听1099端口。

接着,我们定义远程访问层的Spring配置proxy.xml内容,如下所示:

[xhtml] view plain copy
  1. <?xmlversion="1.0"encoding="UTF-8"?>
  2. <beansxmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
  5. <beanid="proxy"class="org.springframework.jmx.access.MBeanProxyFactoryBean">
  6. <propertyname="connectOnStartup"value="true"/>
  7. <propertyname="objectName"value="mydomain:myjavaobj=MyJavaObject"/>
  8. <propertyname="proxyInterface">
  9. <value>org.shirdrn.spring.jmx.rmi.MyManagedInterfaces</value>
  10. </property>
  11. <propertyname="serviceUrl">
  12. <value>service:jmx:rmi://localhost/jndi/rmi://localhost:1099/jmxrmi</value>
  13. </property>
  14. </bean>
  15. </beans>

最后,启动代理,访问MBean资源,代码如下所示:

[java] view plain copy
  1. packageorg.shirdrn.spring.jmx.rmi;
  2. importorg.apache.log4j.Logger;
  3. importorg.springframework.context.ApplicationContext;
  4. importorg.springframework.context.support.ClassPathXmlApplicationContext;
  5. publicclassProxy{
  6. privatestaticfinalLoggerLOG=Logger.getLogger(Proxy.class);
  7. publicstaticvoidmain(String[]args)throwsException{
  8. ApplicationContextctx=newClassPathXmlApplicationContext(
  9. "org/shirdrn/spring/jmx/rmi/proxy.xml");
  10. LOG.info("Proxyserverstarted.");
  11. MyManagedInterfacesproxy=(MyManagedInterfaces)ctx.getBean("proxy");
  12. Stringmessage=proxy.show();
  13. LOG.info("proxy.show()="+message);
  14. Objectlock=newObject();
  15. synchronized(lock){
  16. lock.wait();
  17. }
  18. }
  19. }

这里,只能访问通过org.shirdrn.spring.jmx.rmi.MyManagedInterfaces接口定义的方法来操作注册到MBean Server中的MBean资源。

你可能感兴趣的:(spring)