Перенос MBean с JBoss 4.x на JBoss 7

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

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

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

В Jboss 4.x наши MBean-компоненты часто выглядят так:

@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 для обертывания цели инъекции любого bean-компонента, который аннотируется соответствующим образом, и выполняет регистрацию JMX в методе postConstruct(): http://code.google.com/p/jmx-annotations/. Кроме того, найденные MBean-компоненты сканируются на предмет аннотаций класса / атрибута / метода / параметра, которые предоставляют описание аннотированного свойства.

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

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

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

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

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

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


person Thomas    schedule 14.02.2012    source источник


Ответы (2)


Singleton EJB с @Startup? http://www.adam-bien.com/roller/abien/entry/singleton_the_simplest_possible_jmx

person Chase    schedule 04.07.2012
comment
Я тоже это видел, но что мне не нравится в этом подходе, так это то, что нам придется вручную вводить код регистрации в каждый MBean (во многих случаях мы не можем использовать суперклассы). Таким образом, в настоящее время мы используем метод, который я описал выше. Тем не менее спасибо за предложение :) - person Thomas; 06.07.2012
comment
Вариантов не много. В JBoss 7 вы программно регистрируете или используете jboss-service.xml. Если вам нужны транзакции, то использование Singleton EJB, вероятно, будет самым простым подходом. Вы можете переместить регистрационный код из mbeans и создать StartupRegistrationBean, который регистрировал все ваши mbean-компоненты аналогично этому расширению CDI. - person Chase; 08.07.2012

Я думаю, что более лаконичный способ сделать это - использовать расширение 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

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

person Zorg    schedule 14.03.2014