0

我在这里问了一个问题,但没有得到答案。然而,我继续搜索,发现了一些可以满足我需求的东西:“ MBeanServerForwarder ”。我阅读了官方的 JavaDoc,但对我来说仍然不清楚。

那么,MBeanServerForwarder 是否作为 MBeanServer 的代理工作?即:我可以用它来拦截MBeans注册表,修改ObjectName并转发给MBeanServer吗?

提前致谢。

4

2 回答 2

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:type=HotspotInternal,serial=-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()));

========== 更新 =============

这是我认为您正在寻找的一个简单示例。请参阅此要点

如果您使用以下选项运行示例:

-Djavax.management.builder.initial=org.helios.jmx.HeliosMBeanServerBuilder
-Dhelios.jmx.renamer.filter=java.util.logging:*

它将覆盖系统的默认 MBeanServerBuilder 并拦截所有 ObjectNames 与java.util.logging:*匹配的 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。

于 2012-04-09T18:29:46.430 回答
1

感谢尼古拉斯。

MBeans注册拦截

我使用代理来拦截所有对带有调用处理程序和调用上下文的 BeanServer 的调用。在调用该方法之前,我使用了几个拦截器来编辑参数(例如 registerMBean 参数)并且它可以工作。

将 MBeanServer 设置为 platformMBeanServer

  1. 尼古拉斯的方法(见他的帖子)
  2. 使用定制的 MBeanServerBuilder

为此,我们必须设置一个系统属性:

-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);

}
于 2012-04-12T13:42:22.000 回答