我目前正在研究http://truevfs.java.net,这是一个 Java 虚拟文件系统。TrueVFS 是模块化的,使用插件架构在运行时加载功能,无需进行任何配置。一些可选插件使用平台 MBeanServer 来注册具有已定义 ObjectName 的 MBean,以进行监视和管理。
现在我的一些用户正在他们的 WAR 中捆绑 TrueVFS JAR 以部署到 Tomcat 等。除非它们包含启用 JMX 的插件之一并在不同的上下文中部署多个 WAR 实例,否则这工作正常。
这不起作用,因为每个 Web 应用程序都有自己的启用 JMX 插件的类加载器定义,但是它们都将共享相同的平台 MBeanServer 并使用相同的 ObjectNames 来注册它们的 MBean,因此会发生冲突。
现在我该如何解决这个问题?我已经抽象了 MBeanServer 查找,以便可以将其提取到另一个插件中,但是我无法确定一个普遍适用的策略,我应该使用哪个 MBeanServer 来注册我的 MBean。
我搜索了这个主题并找到了一些WebLogic 的文档,这表明我应该使用 JNDI 查找 MBeanServer。但是,这似乎特定于 WebLogic。
没有通用的一刀切方法吗?
更新:
这是使用附加属性来识别 Web 应用程序定义的类加载器的快速概念验证:
import java.lang.management.ManagementFactory;
import javax.management.JMX;
import javax.management.MBeanServer;
import javax.management.ObjectName;
public class Messenger implements MessengerMXBean {
private static MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
public static void main(String[] args ) throws Exception {
register("one");
register("two");
find();
System.out.println("Waiting for interrupt...");
Thread.sleep(Long.MAX_VALUE);
}
private static void register(String context) throws Exception {
mbs.registerMBean(new Messenger(),
new ObjectName(":type=Messenger,context=" + context));
}
private static void find() throws Exception {
for (ObjectName name : mbs.queryNames(new ObjectName(":type=Messenger,*"), null))
System.out.println(JMX.newMXBeanProxy(mbs, name, MessengerMXBean.class).getMessage());
}
public String getMessage() { return "Hello world!"; }
}
public interface MessengerMXBean { String getMessage(); }
正如预期的那样,该程序注册了两个 Messenger MBean,找到它们并打印它们的“Hello world!”。信息。
但是,这种解决方案也有缺点:
- 我必须模拟一个附加属性作为标识符。理想情况下,这将是类加载器的标识符,这样我就可以保持通用性,即不必仅为 Web 应用程序做特殊考虑。
- 现在查找 MBean 需要考虑多个类加载器的特殊情况,即 MBean 的多个实例,它们的区别仅在于它们的附加限定符,即使应用程序独立运行。
这些都是严重的限制,但我似乎没有更好的选择,所以我可能会走这条路。