Tomcat JMX - 连接到服务器但无法找到我想要的MBean

zig*_*ggy 5 java tomcat jmx

我正在尝试编写一个客户端实用程序,通过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();
             }  
          }
         }
Run Code Online (Sandbox Code Playgroud)

我有一个我在互联网上找到的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)
Run Code Online (Sandbox Code Playgroud)

几个问题

  • 网址是否正确?我知道端口号是正确的,但我不确定服务名称.我在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.由于我没有创建任何新的Mbeans但只读取现有的值,我是否需要配置一个监听器?

编辑

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

MBeanServerConnection conn = jmxc.getMBeanServerConnection(); 
System.out.println("Query2  : " + conn.queryMBeans(null, null)); 
Run Code Online (Sandbox Code Playgroud)

这确实返回了一些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\""));
Run Code Online (Sandbox Code Playgroud)

以上是错误的,因为mbsc.getAttribute的第二个参数应该是Mbean中的属性而不是String名称.

这给了我正确的属性值

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")
Run Code Online (Sandbox Code Playgroud)

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

谢谢

krt*_*tek 5

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

这是正确的:

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

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

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

要测试查询字符串,请使用JMX控制台等工具.

  • 是的 - 因为您确实打开了与Tomcat JVM的连接,然后忘记它并请求本地JVM的JMX服务器.您必须进一步使用该连接.这是我的观点. (2认同)