JMX Notification listener无法正常触发监听的问题排查
问题现象
3个主类分别在独立命令行窗口按Main1→Main2→Main3顺序启动:
- Main1负责注册MBean
- Main2负责给目标MBean添加通知监听器
- Main3负责修改MBean的属性值
预期执行Main3后,Main2窗口输出Received notification!,实际无任何输出。
相关代码
Main1(注册MBean)
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:9999/server"); JMXConnector connector = JMXConnectorFactory.newJMXConnector(url, null); connector.connect; MBeanServerConnection server = connector.getMBeanServerConnection(); ObjectName objNm = new ObjectName("Qwerty:type=server1"); server = createMBean(SampleCnt.class.getName(), objNm);
Main2(添加监听器)
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:9999/server"); JMXConnector connector = JMXConnectorFactory.newJMXConnector(url, null); connector.connect; MBeanServerConnection server = connector.getMBeanServerConnection(); ObjectName objNm = new ObjectName("Qwerty:type=server1"); if (server.isRegistered(objNm)) { CntListener listener = new CntListener(); server.addNotificationListener(objNm, listener, null,null); }
Main3(修改MBean属性)
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:9999/server"); JMXConnector connector = JMXConnectorFactory.newJMXConnector(url, null); connector.connect; MBeanServerConnection server = connector.getMBeanServerConnection(); ObjectName objNm = new ObjectName("Qwerty:type=server1"); if (server.isRegistered(objNm)) { server.setAttribute(objNm, new Attribute("cnt", 1)); }
配套类定义
SampleCntMBean接口
public interface SampleCntMBean { public int getCnt(); public void setCnt(int cnt); }
SampleCnt MBean实现类
public class extends NotificationBroadcasterSupport implements SampleCntMBean { volatile private int cnt = 0; public int getCnt() { return cnt; } public void setCnt(int cnt) { this.cnt = cnt; } }
自定义通知监听器
public class CntListener implements NotificationListener { public void handleNotification(Notification notification, Object handback) { System.out.println("Received notification!"); } }
故障原因
监听器未触发的核心问题如下:
MBean属性修改逻辑未主动发送通知
SampleCnt类虽然继承了NotificationBroadcasterSupport获得了通知发送能力,但setCnt方法仅完成了属性值赋值,没有调用sendNotification()方法发送属性变更事件。JMX的MBean不会自动为属性修改操作触发通知,所有通知都需要业务代码手动构造并发送,监听器没有收到事件自然不会执行打印逻辑。代码存在多处语法、API调用错误,会直接导致编译/运行失败
- 三个主类中的
connector.connect;写法语法错误,connect是方法,必须加括号调用:connector.connect(); - Main1中
server = createMBean(SampleCnt.class.getName(), objNm);调用逻辑错误:createMBean是MBeanServerConnection实例的方法,需要通过server.createMBean(...)调用,且该方法返回值为ObjectInstance类型,不能直接赋值给MBeanServerConnection类型的server变量 - SampleCnt类定义缺失类名,
public class extends NotificationBroadcasterSupport需要补全类名:public class SampleCnt extends NotificationBroadcasterSupport
- Main2进程生命周期问题
如果Main2添加完监听器后代码直接执行结束、进程退出,也无法收到后续Main3触发的通知,需要保持Main2进程持续运行等待事件。
修复方式
- 修正上述所有语法、API调用错误
- 改造
SampleCnt类的setCnt方法,属性变更后主动发送属性变更通知,参考实现:
public class SampleCnt extends NotificationBroadcasterSupport implements SampleCntMBean { volatile private int cnt = 0; // 通知自增序列号 private long notifySeq = 0; public int getCnt() { return cnt; } public void setCnt(int cnt) { int oldValue = this.cnt; this.cnt = cnt; // 构造属性变更通知并发送 AttributeChangeNotification changeNotify = new AttributeChangeNotification( this, notifySeq++, System.currentTimeMillis(), "cnt属性值已修改", "cnt", "int", oldValue, cnt ); sendNotification(changeNotify); } }
- Main2添加完监听器后,加线程等待逻辑保持进程存活,比如加
Thread.sleep(Long.MAX_VALUE);避免进程直接退出。
内容的提问来源于stack exchange,提问作者user4687994
相关产品推荐
相关产品推荐

