以编程方式访问Tomcat中的内置MBean

时间:2013-07-03 20:35:59

标签: tomcat jmx mbeans

基本上我正在尝试修改本教程中的代码:http://docs.oracle.com/javase/tutorial/jmx/remote/custom.html 这样我就可以从这里描述的tomcat访问MBean:http://wiki.apache.org/tomcat/FAQ/Monitoring

访问JMX Bean时没有问题java.lang:type =来自代码的内存,因为它的接口是在java.lang中定义的。这是代码示例:

    ObjectName mbeanName = new ObjectName("java.lang:type=Memory");
    MemoryMXBean mxbeanProxy2 = JMX.newMXBeanProxy(mbsc, mbeanName, MemoryMXBean.class, true);
    MemoryUsage memUsage = mxbeanProxy2.getHeapMemoryUsage();
    echo("\nMemory Utilization: " + (memUsage.getUsed()/(double)memUsage.getMax()) * 100 +  "%");

这里mbsc是MBeanServerConnection的一个实例。 问题是,当我试图以类似的方式访问tomcat中的内置MBean时,我遇到了一个问题,我找不到为任何tomcat MBean定义的任何接口。我可以从JConsole监视MBean,但为此我需要能够从代码中执行此操作。我发现它可以通过以下方式完成:

ObjectName mbeanName2 = new ObjectName("Catalina:type=ThreadPool,name=\"http-apr-8080\"");
Object value = mbsc.getAttribute(mbeanName, "name");

但这给了我这个例外: 线程“main”中的异常javax.management.AttributeNotFoundException:没有这样的属性:com.sun.jmx.mbeanserver中的名称......

我觉得我错过了一些相当基本的东西。但有关这方面的信息似乎非常有限,谷歌没有多大帮助。

2 个答案:

答案 0 :(得分:2)

我认为你的第二段代码中有一个拼写错误。您为Catalina ThreadPool创建了一个名为 mbeanName2 的新ObjectName,但是当您尝试检索属性“name”时,您仍然使用 mbeanName

所以它应该是:

ObjectName mbeanName2 = new ObjectName("Catalina:type=ThreadPool,name=\"http-apr-8080\"");
Object value = mbsc.getAttribute(mbeanName2, "name");

除此之外,您的代码应该可以正常工作。

答案 1 :(得分:1)

今天我遇到了与上面描述的Oz0234相同的问题(在Windows上使用TomEE 1.7.0),但我暂时不明白为什么ProxyBean解决方案根本不适用于任何Catalina对象。

它适用于MBeanServerConnection。 getAttribute (objectName,attribute)方法但使用代理bean方法 不起作用。我检查并测试了很多。

最后我发现了为什么会这样。答案是 Catalina域中的属性名称以小写字母开头,而其他域中的属性名称(java.lang,java.nio,openejb,...)以upper开头如下所述:http://docs.oracle.com/javase/7/docs/api/javax/management/JMX.html

我已经提取了最相关的部分:

MyMXBean proxy = JMX.newMXBeanProxy(mbs, name, MyMXBean.class);

假设,例如,MyMXBean看起来像这样:

public interface MyMXBean {
  public String getSimpleAttribute();
  public void setSimpleAttribute(String value);
  public MemoryUsage getMappedAttribute();
  public void setMappedAttribute(MemoryUsage memoryUsage);
  public MemoryUsage someOperation(String param1, MemoryUsage param2);
}

Then proxy.getSimpleAttribute() will result in a call to
mbs.getAttribute(name, "SimpleAttribute").

您可以看到上面的示例,该属性的名称以大写字母“ S ”implementsAttribute开头,作为代理bean getter name get S impleAttribute。不幸的是,这与bean的getter / setter命名约定所描述的正好相反。

此外,我还检查了JMX连接上可用的其他Tomcat Domain Objects(Catalina,Users)属性,并且我还比较了其他一些属性。如果属性名称以大写字母开头,则bean代理将起作用。如果它以小写字母开头,则只有getAttribute方法有效,如下所示:

JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:9999/jmxrmi");
try(JMXConnector jmxc = JMXConnectorFactory.connect(url)) {
  MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
  ObjectName mbeanName = new ObjectName("Catalina:type=Manager,context=/,host=localhost");
  Object value = mbsc.getAttribute(mbeanName, "activeSessions");
}

所以你需要注意你选择哪种方法。