我问了一个问题here,但我没有得到答案。然后,我继续搜索,找到了可以满足我需求的东西:“ MBeanServerForwarder ”。我阅读了官方JavaDoc,但对我来说仍然不太清楚。
那么,MBeanServerForwarder是否可以作为MBeanServer的代理? ie:我可以使用它拦截MBeans注册表,在ObjectName中进行修改并将其转发到MBeanServer吗?
提前致谢。
答案 0 :(得分:1)
是的,但这不是必需的。您只需要实现 MBeanServer 接口并覆盖 registerMBean 方法(可能还有 unregisterMBean 方法)。
使用真正的MBeanServer作为委托,这里的实现可能是这样的:
public class AltObjectNameMBeanServer implements MBeanServer {
protected final MBeanServer innerServer;
protected final ObjectName filter;
public AltObjectNameMBeanServer(MBeanServer innerServer, ObjectName filter) {
this.innerServer = innerServer;
this.filter = filter;
}
public ObjectInstance registerMBean(Object object, ObjectName name) throws InstanceAlreadyExistsException,
MBeanRegistrationException, NotCompliantMBeanException {
if(filter.apply(name)) {
name = reformat(name);
}
return innerServer.registerMBean(object, name);
}
public static ObjectName reformat(ObjectName on)
try {
int id = on.toString().hashCode();
return new ObjectName(new StringBuilder(on.toString()).append(",serial=").append(id).toString());
} catch (Exception e) {
throw new RuntimeException("Failed to reformat [" + on + "]", e);
}
}
// ======== Put direct delegates for all other methods =======
}
样本用法:
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
AltObjectNameMBeanServer rr = new AltObjectNameMBeanServer(server, new ObjectName("*:*"));
Class clazz = Class.forName("sun.management.HotspotInternal");
HotspotInternalMBean obj = (HotspotInternal)clazz.newInstance();
ObjectInstance oi = rr.registerMBean(new StandardMBean(obj, HotspotInternalMBean.class), new javax.management.ObjectName("sun.management:type=HotspotInternal"));
System.out.println("ObjectName:" + oi.getObjectName());
输出结果为:
的ObjectName:sun.management:类型= HotspotInternal,串行= -441253090
通过一些反思,您可以设置新的MBeanServer impl。在 java.lang.management.ManagementFactory 的 platformMBeanServer 字段中,您将永久覆盖JVM代理的MBean注册。
==========更新============
此代码段演示了如何破解平台MBeanServer以提供备用(或包装)MBeanServer(使用上面的AltObjectNameMBeanServer的 rr 实例:
Field serverField = ManagementFactory.class.getDeclaredField("platformMBeanServer");
serverField.setAccessible(true);
serverField.set(null, rr);
System.out.println("Equal:" + (rr==ManagementFactory.getPlatformMBeanServer()));
==========更新============
这是我认为您正在寻找的一个简单示例。 请参阅this gist。
如果您使用以下选项运行示例:
-Djavax.management.builder.initial=org.helios.jmx.HeliosMBeanServerBuilder
-Dhelios.jmx.renamer.filter=java.util.logging:*
它将覆盖系统的默认MBeanServerBuilder,并拦截所有符合 java.util.logging:* 的ObjectNames的MBean注册。
当 main 运行时,它将打印所有平台MBeanServer MBean ObjectNames,输出将如下所示:
MBeanServer Interceptor Test
java.lang:type=MemoryPool,name=PS Eden Space
java.lang:type=Memory
java.lang:type=MemoryPool,name=PS Survivor Space
java.lang:type=GarbageCollector,name=PS MarkSweep
java.lang:type=MemoryPool,name=Code Cache
java.lang:type=Runtime
java.lang:type=ClassLoading
java.lang:type=Threading
java.lang:type=Compilation
com.sun.management:type=HotSpotDiagnostic
java.lang:type=MemoryPool,name=PS Perm Gen
java.util.logging:type=Logging,serial=-132046985
java.lang:type=OperatingSystem
java.lang:type=GarbageCollector,name=PS Scavenge
java.lang:type=MemoryPool,name=PS Old Gen
java.lang:type=MemoryManager,name=CodeCacheManager
JMImplementation:type=MBeanServerDelegate
注意重命名 java.util.logging:type = Logging,serial = -132046985
或者,您可以创建自己的HeliosMBeanServer构建器实例,定义域名,过滤器和重命名策略,并创建自己的MBeanServer,而不是使用平台MBeanServer。
答案 1 :(得分:1)
感谢尼古拉斯。
我使用Proxy来拦截所有使用Invocation Handler和Invocation Context的BeanServer调用。我在调用方法之前使用了几个拦截器来编辑参数(例如registerMBean参数)并且它可以工作。
为此,我们必须设置一个系统属性:
-Djavax.management.builder.initial=my.own.MBeanServerBuilder
您可能会收到NotFoundClassException。要解决此问题,请确保Thread.CurrentThread()的类加载器与创建MBeanServer的类相同。
您自己的MBeanServerBuilder必须扩展MBeanServerBuilder类。根据您的需要,覆盖方法以添加信息。对于我的用例,我必须返回MBeanServer的代理,所以我创建一个新的MBeanServer,创建代理并返回它。
public MBeanServer newMBeanServer(String defaultDomain,
MBeanServer outer,
MBeanServerDelegate delegate) {
MBeanServer origin = super.newMBeanServer(defaultDomain, outer, delegate);
return (MBeanServer) Proxy.newProxyInstance(origin.getClass().getClassLoader(), new Class<?>[]{MBeanServer.class}, handler);
}