Поведение MBeanServerForwarder

Я задал вопрос здесь, но не получил ответа. Тем не менее, я продолжаю поиски и нашел кое-что, что может удовлетворить мои потребности: "MBeanServerForwarder". Я прочитал официальный JavaDoc, но мне все еще не ясно.

Итак, работает ли MBeanServerForwarder как прокси для MBeanServer? то есть: Могу ли я использовать его для перехвата реестра MBeans, внесения изменений в ObjectName и перенаправления его на MBeanServer?

Заранее спасибо.


person Mohammed    schedule 09.04.2012    source источник


Ответы (2)


Да, но это совсем не обязательно. Вам нужно только реализовать интерфейс 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. в поле platformMBeanServer в java.lang.management.ManagementFactory, и вы навсегда переопределите регистрацию MBean агента JVM.

========== Обновление =============

Этот фрагмент кода демонстрирует, как вы можете взломать платформу MBeanServer, чтобы предоставить альтернативный (или обернутый) MBeanServer (используя экземпляр rr AltObjectNameMBeanServer из приведенного выше:

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 по умолчанию и перехватит все регистрации MBean с именами объектов, соответствующими java.util.logging:*.

Когда main запустится, он напечатает все имена объектов MBean MBeanServer платформы, и вывод будет выглядеть следующим образом:

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.

person Nicholas    schedule 09.04.2012
comment
Спасибо, Николай, это именно то, что я хочу. - person Mohammed; 10.04.2012
comment
У вас есть идея, как установить новый импл MBeanServer в платформе MBeanServer или как добавить его в mBeanServerList в MBeanServerFactory? - person Mohammed; 11.04.2012
comment
Большое спасибо, это работает. Однако это решение очень зависит от имени атрибута, и если однажды кто-то решит его изменить, оно не сработает. Я посмотрел со стороны MBeanServerBuilder, и там есть системное свойство, указывающее, какой класс MBeanServerBuilder использовать. Он, вероятно, тяжелый, но более элегантный. Можно ли сделать наш собственный MBeanServerBuilder для определения прокси-сервера в качестве основного mbs, который только перехватывает вызовы, вносит изменения и делегирует исходному mbs? - person Mohammed; 12.04.2012

Спасибо Николаю.

Перехват регистрации MBeans

Я использовал прокси для перехвата всех вызовов BeanServer с помощью обработчика вызовов и контекста вызова. Я использовал несколько перехватчиков для редактирования параметров (например, параметров регистрации MBean) перед вызовом метода, и он работает.

Установите MBeanServer как платформуMBeanServer

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

}
person Mohammed    schedule 12.04.2012