【问题标题】:Tomcat JMX - Connecting to server but cant find the MBean i wantTomcat JMX - 连接到服务器但找不到我想要的 MBean
【发布时间】:2011-01-05 18:46:45
【问题描述】:

我正在尝试编写一个客户端实用程序来通过 JMX 连接到 Tomcat 并查看连接数据源的状态。 我在 $CATALINA_HOME/bin/setenv.bat 中设置了以下 VM 参数并重新启动了 Tomcat

设置 JAVA_OPTS=-Xms512M -Xmx1024M -XX:MaxPermSize=256M %JAVA_OPTS% 设置 CATALINA_OPTS=-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9004 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false %CATALINA_OPTS%

我对 JMX 不是很熟悉,所以我只是在玩弄它来感受一下。 我正在编写的实用程序将在 Tomcat 之外运行。我编写了以下测试来尝试访问 Tomcat 中的数据源 Mbean 对象 但由于某种原因,它没有找到它。

    public class GuiMonitor {
      public static void main(String[] args){

       try{
        JMXServiceURL url = new JMXServiceURL(
             "service:jmx:rmi:///jndi/rmi://localhost:9004/jmxrmi");
            JMXConnector jmxc = JMXConnectorFactory.connect(url, null);

            final List<MBeanServer> servers = new LinkedList<MBeanServer>();

            servers.add(ManagementFactory.getPlatformMBeanServer());
            servers.addAll(MBeanServerFactory.findMBeanServer(null));

            System.out.println("MbeanServers " + servers.size()); 

            for(final MBeanServer server : servers){
              System.out.println("Server : " + server.getClass().getName());
             }

            MBeanServer mbsc = ManagementFactory.getPlatformMBeanServer();
            System.out.println(mbsc.queryMBeans(null, null));
            ObjectName on = new ObjectName("Catalina:type=DataSource,path=/appdb,host=localhost,class=javax.sql.DataSource,name=\"jdbc/appdb\"");
            System.out.println("ObjectName : " + on.toString());
            System.out.println(mbsc.getAttribute(on, "Catalina:type=DataSource,path=/appdb,host=localhost,class=javax.sql.DataSource,name=\"jdbc/appdb\""));

       } catch (Exception e) {
                 e.printStackTrace();
             }  
          }
         }

我有一个在互联网上找到的 JSP 页面,当我上传到 webapps 文件夹并运行它时,它会显示所有可用的 Tomcat 中的 MBean。我上面使用的对象字符串/名称来自我使用的 jsp 页面和 Jconsole 上报告的名称,因此它确实存在。

上面程序的输出如下所示

     MbeanServers 2

     Server : com.sun.jmx.mbeanserver.JmxMBeanServer
     Server : com.sun.jmx.mbeanserver.JmxMBeanServer

     [com.sun.management.OperatingSystem[java.lang:type=OperatingSystem], sun.management.MemoryPoolImpl[java.lang:type=MemoryPool,name=Tenured Gen], sun.management.MemoryPoolImpl[java.lang:type=MemoryPool,name=Perm Gen], java.util.logging.Logging[java.util.logging:type=Logging], sun.management.CompilationImpl[java.lang:type=Compilation], javax.management.MBeanServerDelegate[JMImplementation:type=MBeanServerDelegate], sun.management.MemoryImpl[java.lang:type=Memory], sun.management.MemoryPoolImpl[java.lang:type=MemoryPool,name=Survivor Space], sun.management.RuntimeImpl[java.lang:type=Runtime], sun.management.GarbageCollectorImpl[java.lang:type=GarbageCollector,name=Copy], sun.management.MemoryPoolImpl[java.lang:type=MemoryPool,name=Eden Space], sun.management.GarbageCollectorImpl[java.lang:type=GarbageCollector,name=MarkSweepCompact], sun.management.ThreadImpl[java.lang:type=Threading], sun.management.MemoryPoolImpl[java.lang:type=MemoryPool,name=Perm Gen [shared-ro]], sun.management.MemoryPoolImpl[java.lang:type=MemoryPool,name=Perm Gen [shared-rw]], sun.management.HotSpotDiagnostic[com.sun.management:type=HotSpotDiagnostic], sun.management.ClassLoadingImpl[java.lang:type=ClassLoading], sun.management.MemoryManagerImpl[java.lang:type=MemoryManager,name=CodeCacheManager], sun.management.MemoryPoolImpl[java.lang:type=MemoryPool,name=Code Cache]]
     ObjectName : Catalina:type=DataSource,path=/appdb,host=localhost,class=javax.sql.DataSource,name="jdbc/appdb"

     javax.management.InstanceNotFoundException: Catalina:type=DataSource,path=/appdb,host=localhost,class=javax.sql.DataSource,name="jdbc/appdb"
      at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.getMBean(DefaultMBeanServerInterceptor.java:1094)
      at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.getAttribute(DefaultMBeanServerInterceptor.java:662)
      at com.sun.jmx.mbeanserver.JmxMBeanServer.getAttribute(JmxMBeanServer.java:638)
      at com.bt.c21.c21mon.C21GuiMonitor.main(C21GuiMonitor.java:39)

几个问题

  • URL 是否正确?我知道端口号是正确的,但我不确定服务名称。我在 URL 上使用的服务名称“jmxrmi”只是我在我一直在查看的示例之一中看到的。

我感觉这是连接到不同的 MBeanServer。我怀疑这是因为如果您查看 mbsc.queryMBeans(null, null) 的输出,则没有特定于 tomcat 的内容。 Tomcat 实例使用什么服务名称?

  • 如果 URL 正确,那么服务名称是否总是 jmxrmi?以及为什么找不到“Catalina:type=DataSource,path=/appdb,host=localhost,class=javax.sql.DataSource,name=\"jdbc/appdb\"" 条目?

  • 我已经看到很多关于如何做到这一点的示例,并且大多数使用不同的方法来获取 MbeanServer。我见过的几个例子是

    ManagementFactory.getPlatformMBeanServer() MBeanServerFactory.findMBeanServer(null) getMBeanServerConnection()

  • 如前所述,我正在编写的实用程序是一个普通的 java 应用程序,它将在 tomcat 之外运行。还有其他我错过的配置吗?我一直在查看几个示例,大多数都在谈论创建 MBean,并且通常会引用 Listeners。由于我没有创建任何新的 Mbean,而只是读取现有 Mbean 的值,我是否需要配置一个侦听器?

编辑

似乎 getPlatformMbeanServer() 没有返回正确的 JVM 实例。我尝试了以下

MBeanServerConnection conn = jmxc.getMBeanServerConnection(); 
System.out.println("Query2  : " + conn.queryMBeans(null, null)); 

这确实会返回一些 Tomcat 特定的值。但我仍然无法获取 jdbc/appdb 数据源。

krtek - 我将无法使用 JMX 控制台,因为我打算手动完成所有操作以实现自动化。

编辑 2

好的,我知道我做错了什么。最初我试图将值检索为

MBeanServerConnection conn = jmxc.getMBeanServerConnection(); 
ObjectName on = new ObjectName("Catalina:type=DataSource,path=/appdb,host=localhost,class=javax.sql.DataSource,name=\"jdbc/appdb\"");
mbsc.getAttribute(on, "Catalina:type=DataSource,path=/appdb,host=localhost,class=javax.sql.DataSource,name=\"jdbc/appdb\""));

上面是错误的,因为 mbsc.getAttribute 的第二个参数应该是 Mbean 中的属性而不是字符串名称。

这给了我正确的属性值

MBeanServerConnection conn = jmxc.getMBeanServerConnection(); 
ObjectName on = new ObjectName("Catalina:type=DataSource,path=/appdb,host=localhost,class=javax.sql.DataSource,name=\"jdbc/appdb\"");
mbsc.getAttribute(on, "numIdle")

我还将我使用的 MBeanServer 从 getPlatformMbeanServer() 更改为 getMBeanserverConnection()。我必须承认我不太了解其中的区别,因为 Tomcat 与 getPlatformMbeanServer() 返回的 JVM 运行在同一个 JVM 上。这是否意味着 getPlatformMbeanServer() 只会返回特定于太阳的 Mbean?和 getMBeanserverConnection() 将包括两者?

谢谢

【问题讨论】:

  • 请注意最后一句:Tomcat 肯定不是运行在同一个 JVM 中,它是运行在同一台 PC 上但运行在不同的 JVM 上。区别很简单:jmxc.getMBeanServerConnection() 从远程连接(Tomcat JVM)返回 JMX 服务器实例。 ManagementFactory.getPlatformMBeanServer() 从本地 JVM 返回 JMX 服务器。
  • 嗨 Krtek - 本地 JVM 是指我用来连接到 Tomcat 的应用程序正在运行的 JVM 吗?

标签: java tomcat jmx


【解决方案1】:

那是因为您正在为您的客户端 JVM 获取 JMX 服务器实例,而不是 Tomcat 实例。

这是对的:

JMXServiceURL url = new JMXServiceURL(
    "service:jmx:rmi:///jndi/rmi://localhost:9004/jmxrmi");
JMXConnector jmxc = JMXConnectorFactory.connect(url, null);

但你应该继续这样的事情:

MBeanServerConnection conn = jmxc.getMBeanServerConnection(); 
Set result = conn.queryMBeans(null, 
"Catalina:type=DataSource,path=/appdb,host=localhost,class=javax.sql.DataSource");

要测试您的查询字符串,请使用JMX console 等工具。

【讨论】:

  • 嗨 krtrek,只是出于我的好奇,您是如何得出结论 ziggy 正在获取客户端 JVM 的 JMX 服务器实例,而不是 Tomcat 实例。他确实表明 Tomcat 在端口 9004 上运行
  • ManagementFactory.getPlatformMBeanServer() 返回当前 JVM 实例的 JMX 服务器,而不是远程的。
  • 我在 Tomcat 未运行时再次重新运行该程序,并收到以下错误“连接拒绝托管:本地主机;”。如果我将端口号更改为 9004 以外的端口号,我也会收到同样的错误。顺便说一下,tomcat 实例是本地的而不是远程的)
  • 是的 - 因为您确实打开了与 Tomcat JVM 的连接,然后忘记了它并请求本地 JVM 的 JMX 服务器。您必须进一步使用该连接。这就是我的观点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-30
  • 2018-07-26
相关资源
最近更新 更多