Подтвердить что ты не робот

Порт MBean от JBoss 4.x до JBoss 7

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

Я искал довольно долгое время, но либо я не способен выполнить правильный поисковый запрос, либо я пропускаю часть знаний, чтобы устранить разрыв между определением 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 (я в настоящее время использую порт Dimitris Andreadis)
  • предоставить описания методов/параметров

Обновление

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

Сначала я нашел эту проекцию, которая использует CDI для переноса цели инъекции любого bean, который аннотируется соответственно, и регистрирует JMX в методе postConstruct(): http://code.google.com/p/jmx-annotations/. Кроме того, найденные MBeans сканируются для аннотаций class/attribute/method/parameter, которые предоставляют описание для аннотированного свойства.

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

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

Ниже приведен краткий обзор процедуры запуска:

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

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

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

4b9b3361

Ответ 2

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

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