【发布时间】: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 吗?