Порт MBean из JBoss 4.x в JBoss 7 - PullRequest
       28

Порт MBean из JBoss 4.x в JBoss 7

13 голосов
/ 14 февраля 2012

В настоящее время мы переносим некоторые из наших проектов с JBoss 4.x на JBoss 7. Пока все работает нормально, за исключением нашего MBean, который мы обычно используем для обеспечения простых операций управления.

Я уже давно ищу, но либо не могу найти правильный поисковый запрос, либо мне не хватает каких-то знаний, чтобы преодолеть разрыв между определением MBean в JBoss 4.x и JBoss 7.

Таким образом, мы надеемся, что кто-то может дать подсказку о том, что мне может не хватать или о том, где мне придется читать (возможно, некоторую документацию, примеры и т.

В Jboss 4.x наши MBeans часто выглядят так:

@Service( objectName = "Domain:Name=SomeMBean",
  xmbean="resource:<path-to-xmbean.xml>")
class SomeMBean 
{
  @EJB
  private SomeService someService;    

  public String someOperation()
  {
     someService.doSomething();
     return "success";
  }
}

Мы использовали аннотацию @Service для определения имени объекта и дескриптора xmbean, и JBoss автоматически зарегистрировал бы эти mbeans.

Очевидно, в JBoss 7 аннотация @Service больше не существует, и поэтому необходим другой подход.

Пока мне удалось зарегистрировать MBean вручную на сервере mbean платформы, но я бы предпочел, чтобы JBoss сделал это автоматически. Кроме того, мне пока не удавалось дать описания методов / параметров (хотя это было бы неплохо иметь функцию).

Я повторю вопрос для ясности:

Как бы я определил MBean в JBoss 7 (Java EE 6), который предоставляет следующие функции?

  • автоматическое развертывание
  • доступ к EJB
  • доступно через JConsole или JMX-Console (в настоящее время я использую порт Димитриса Андредиса)
  • предоставить описания методов / параметров

Обновление

Вот что я получил до сих пор:

Во-первых, я нашел эту проекцию, которая использует CDI для обертывания цели внедрения любого компонента, который соответствующим образом помечается, и выполняет регистрацию JMX в методе postConstruct(): http://code.google.com/p/jmx-annotations/. Кроме того, сканируются найденные MBean-компоненты для аннотаций класса / атрибута / метода / параметра, которые предоставляют описание для аннотированного свойства.

Однако метод postConstruct(), по-видимому, не вызывается для EJB (я предполагаю, что это не для того, чтобы конфликтовать с контейнером EJB). Таким образом, теперь MBean-компоненты должны быть не EJB-компонентами, а обычными компонентами CDI.

Таким образом, однако, имеет недостаток, что MBeans не создаются автоматически. Чтобы преодолеть это, существует одноэлементный компонент, который при запуске перебирает все компоненты в BeanManager и создает экземпляр каждого найденного MBean. Поскольку у MBean все еще есть цель внедрения, его метод postConstruct() не будет вызываться, и компонент будет зарегистрирован на сервере MBean.

Вот краткий обзор процедуры запуска:

  • пользовательское расширение CDI сканирует каждый компонент CDI для пользовательской аннотации @MBean
  • для каждого понятного MBean, в который наматывается мишень для инъекции
  • Запустится одноэлементный компонент, который в своем методе @PostConstruct создаст экземпляры MBeans
  • Будет вызван метод postConstruct() цели внедрения MBean, и, таким образом, MBean будет зарегистрирован на сервере MBean

Одним из недостатков этого метода будет отсутствующий контекст транзакции при выполнении методов MBean (любые вызовы EJB будут выполняться в контексте транзакции). Однако это может быть исправлено с помощью перехватчика CDI, который при необходимости предоставит контекст транзакции. Похоже, у проекта Seam есть соответствующие перехватчики.

Я до сих пор не уверен, что это разумный и стабильный подход, поэтому любые конструктивные комментарии, подсказки и т. Д. Приветствуются.

Ответы [ 2 ]

3 голосов
/ 04 июля 2012
1 голос
/ 14 марта 2014

Я думаю, что более краткий способ сделать это - использовать расширение CDI.Пожалуйста, взгляните на решение, которое мы используем:

@Documented
@Retention(value=RUNTIME)
@Target(value=TYPE)
@Inherited
public @interface MBean {
    String value() default "";
}

...

Это рабочий код расширения CDI:

public class ManagementExtension implements Extension {

    private static Logger log = LoggerFactory
            .getLogger(ManagementExtension.class);

    public <T> void processInjectionTarget(@Observes ProcessInjectionTarget<T> pit) {

        // check if the MBean annotation is present
        AnnotatedType<T> at = pit.getAnnotatedType();
        if (at.isAnnotationPresent(MBean.class)) {
            // it makes sense to register JMX interfaces only for singletons
            if (!at.isAnnotationPresent(Singleton.class)) {
                log.warn("Ignoring attemt to register JMX interface for a non-singleton EJB: "
                        + at.getJavaClass().getName());
                return;
            }

            try {
                // decorate the InjectionTarget
                InjectionTarget<T> delegate = pit.getInjectionTarget();
                InjectionTarget<T> wrapper = new JmxInjectionTarget<T>(delegate, getObjectName(at));

                // change the InjectionTarget with the decorated one
                pit.setInjectionTarget(wrapper);
            } catch (Exception e) {
                log.warn("Cannot get JMX object name for: " + at.getJavaClass().getName(), e);
            }

        }
    }

    private <T> ObjectName getObjectName(AnnotatedType<T> at) throws MalformedObjectNameException {

        String name = at.getAnnotation(MBean.class).value();

        if (name.isEmpty()) {
            name = at.getJavaClass().getPackage().getName() + ":type="
                    + at.getJavaClass().getSimpleName();
        }

        return new ObjectName(name);
    }

    private class JmxInjectionTarget<T> implements InjectionTarget<T> {

        private final InjectionTarget<T> d;
        private final ObjectName objectName;

        public JmxInjectionTarget(InjectionTarget<T> delegate, ObjectName objectName) {
            this.d = delegate;
            this.objectName = objectName;
        }
        @Override
        public void dispose(T instance) {
            d.dispose(instance);
        }

        @Override
        public Set<InjectionPoint> getInjectionPoints() {
            return d.getInjectionPoints();
        }

        @Override
        public T produce(CreationalContext<T> ctx) {
            return d.produce(ctx);
        }

        @Override
        public void inject(T instance, CreationalContext<T> ctx) {
            d.inject(instance, ctx);
            //the next piece of code better be done in postConstruct but...
            //got no idea why but postConstruct never gets called
            //for Singleton EJB bean
            MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
            try {
                if(mBeanServer.isRegistered(objectName))
                mBeanServer.unregisterMBean(objectName);
                mBeanServer.registerMBean(instance, objectName);
            } catch (Exception e) {
                log.warn("Cannot register "+objectName, e);
                return;
            }
            log.info("added JMX registration for: " + objectName);
        }

        @Override
        public void postConstruct(T instance) {
            d.postConstruct(instance);
        }

        @Override
        public void preDestroy(T instance) {
            d.preDestroy(instance);
        }

    }
}

Тогда просто отметьте свой класспо аннотации @Mbean и будет автоматически зарегистрирован на сервере Mbean:

@Startup 
@Singleton 
@MBean("com.company=JmxBindName")
public class SomeService

Работает как шарм)

...