浏览 5545 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2007-07-24
首先让别的程序连接到mbeanServer必须有个serverConnectior 只需在mbeanServer的配置文件中定义一个 <bean id="serverConnector" class="org.springframework.jmx.support.ConnectorServerFactoryBean"/> 即可完成对连接的监听 这样设定是使用默认的及jmxmp协议service:jmx:jmxmp://localhost:9875 你也可以通过使用其他jmx支持的协议RMI,IIOP, Burlap,Hessian,SOAP等, 只要设定objectName和serviceUrl及可 为了方便我们常用的还是jmxmp. server配置好到client了。 client同样需要一个连接器 <bean id="clientConnector" class="org.springframework.jmx.support.MBeanServerConnectionFactoryBean"> <property name="serviceUrl" value="service:jmx:jmxmp://localhost:9875" /> </bean> 简单直观的配置没什么可以说的。 操作mbean. 无论你使用那种方式注册和描述mbean,访问和操作mbean的方式只有一种。就是通过interface创建的代理来访问。 <bean id="proxy" class="org.springframework.jmx.access.MBeanProxyFactoryBean"> <property name="objectName" value="mbean:name=testBean" /> <property name="proxyInterface" value="com.xmlasia.spring.test.jmx.ICommentMBeanManager" /> <property name="server" ref="clientConnector" /> </bean> 同样简单直观,这里注意proxyInterface不是数组类型。你只能设定一个interface,无论server是不是用interface暴露的,只要client的interface于mbeanServer中的匹配就能正确访问 。 如果你不是使用interface暴露的mbean的方法,当你调用不匹配的method时会有 org.springframework.jmx.access.InvalidInvocationException: Operation 'publicMessage' is not exposed on the management interface从客户段抛出。所以在实际应用时最 好能使用interface配置mbean. 测试 public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("/jmxClientContext.xml"); ICommentMBeanManager o = (ICommentMBeanManager)context.getBean("proxy"); o.pause("testid"); o.shutDown(); while(true){ try { Thread.sleep(10000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } 同样client的连接是不阻塞主线程的,同样需要保持主线程的活着。 调用上述代码就能看到server有调用mbean的方法。 通知 jmx有一种机制和向容器通知属性改变,首先我们需要了解NotificationListener package com.xmlasia.spring.test.jmx; import javax.management.Notification; import javax.management.NotificationListener; public class TestNotificationListener implements NotificationListener { @Override public void handleNotification(Notification notification, Object obj) { System.out.println(notification); } } 实现一个NotificationListener,可以看到NotificationListener是标准的jmx接口 当属性值改变时handleNotification将会调用。 使用MBeanExporter的notificationListenerMappings属性将listener和mbean进行mapping <bean id="mBeanExporter" class="org.springframework.jmx.export.MBeanExporter"> <property name="server" ref="mbeanServer" /> <property name="assembler" ref="assembler" /> <property name="beans"> <!-- 将mbean注册到mBeanExporter --> <map> <entry key="mbean:name=testBean" value-ref="mbeanManager" /> </map> </property> <property name="registrationBehaviorName" value="REGISTRATION_REPLACE_EXISTING" /> <property name="notificationListenerMappings"> <map> <!--将所有listener mapping到所有mbean--> <entry key="*"> <bean class="com.xmlasia.spring.test.jmx.TestNotificationListener" /> </entry> </map> </property> </bean> key是同配符,也可以指定到某一个mbean 当我们在client调用.setClientStatus是handleNotification收到的 notification = javax.management.AttributeChangeNotification[source=mbean:name=testBean][type=jmx.attribute.change][message=AttributeChangeDetected] 一般情况下这样的通知没有意义,我们要将他filter掉。 package com.xmlasia.spring.test.jmx; import javax.management.Notification; import javax.management.NotificationFilter; import javax.management.NotificationListener; public class TestNotificationListener implements NotificationListener, NotificationFilter { @Override public void handleNotification(Notification notification, Object obj) { System.out.println(notification); } @Override public boolean isNotificationEnabled(Notification notification) { if (notification instanceof javax.management.AttributeChangeNotification) return false; else return true; } } 同样实现标准的jmx接口NotificationFilter 我们通过判断他的类型进行过滤。 改变配置文件。不使用notificationListenerMappings属性,改用notificationListeners <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <bean id="mbeanManager" class="com.xmlasia.spring.test.jmx.MBeanManager" /> <bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean"> </bean> <bean id="assembler" class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler"> <property name="attributeSource" ref="jmxAttributeSource" /> </bean> <bean id="jmxAttributeSource" class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource" /> <bean id="mBeanExporter" class="org.springframework.jmx.export.MBeanExporter"> <property name="server" ref="mbeanServer" /> <property name="assembler" ref="assembler" /> <property name="beans"> <map> <entry key="mbean:name=testBean" value-ref="mbeanManager" /> </map> </property> <property name="notificationListeners"> <list> <bean class="org.springframework.jmx.export.NotificationListenerBean"> <constructor-arg ref="testNotificationListener" /> <property name="mappedObjectNames"> <list> <value>mbean:name=testBean</value> </list> </property> <property name="notificationFilter" ref="testNotificationListener" /> </bean> </list> </property> </bean> <bean id="testNotificationListener" class="com.xmlasia.spring.test.jmx.TestNotificationListener"/> <bean id="serverConnector" class="org.springframework.jmx.support.ConnectorServerFactoryBean" /> </beans> 完整的配置 我们注入一个spring为我们封装好的NotificationListenerBean,可以将listener,filter,还有objectname方便组织在一起。 这里要特别说明下mappedObjectNames是String[]类的,spring reference中的例子是错误的。 下面我们要自己发布notification package com.xmlasia.spring.test.jmx; import javax.management.Notification; import org.springframework.jmx.export.annotation.ManagedAttribute; import org.springframework.jmx.export.annotation.ManagedOperation; import org.springframework.jmx.export.annotation.ManagedOperationParameter; import org.springframework.jmx.export.annotation.ManagedOperationParameters; import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.jmx.export.notification.NotificationPublisher; import org.springframework.jmx.export.notification.NotificationPublisherAware; @ManagedResource public class MBeanManager implements NotificationPublisherAware { private int clientStatus; private NotificationPublisher publisher; @ManagedOperation(description = "pause a single proccess") @ManagedOperationParameters( { @ManagedOperationParameter(name = "Name of proccess instance", description = "Mandatory") }) public void pause(String n) { System.out.println("pause proccess id :" + n); } @ManagedOperation(description = "shut down the proccess") public void shutDown() { System.out.println("shutting down..."); } public void publicMessage() { System.out.println("public Message to monitor server"); } @ManagedAttribute(description = "client status") public int getClientStatus() { return clientStatus; } @ManagedAttribute(description = "client status") public void setClientStatus(int clientStatus) { this.clientStatus = clientStatus; publisher.sendNotification(new Notification("set",this,0,"client Status changed")); } @Override public void setNotificationPublisher( NotificationPublisher notificationPublisher) { publisher = notificationPublisher; } } 我们只需要implements NotificationPublisherAware 的setNotificationPublisher方法就可以方便的使用 自己的publisher,提供有用的信息到listener中。 Spring会在exporter创建mbean时帮我们传入NotificationPublisher。 Spring对jmx的封装已经看完了。从中可以学到很多Spring的思想和技巧,希望大家能给点意见。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2007-07-25
谢谢你的这三篇文章。
以前没有搞过jmx,只是顺着你的文章,结合sping doc把你提到的例子走了一遍。有个问题: 为什么我用jconsole连不上server呢?用client可以的。 还有一个弱问题:按照你的文章来看,这些例子用rmi完全可以实现,为什么要定义一种新的协议来实现这样的功能的? |
|
返回顶楼 | |
发表时间:2007-07-26
jconsole可以连的,他会自动帮你搜索jvm的pid连过去。
用rmi就需要用到jndi,jnid需要有jndi的容器。比较麻烦。 不如用jmxmp简单直接。把自己application当做server,我个人比较喜好用这个协议 |
|
返回顶楼 | |