14

現在、一部のプロジェクトを JBoss 4.x から JBoss 7 に移植中です。これまでのところ、単純な管理操作を提供するために一般的に使用している MBean を除いて、すべてがうまく機能しているようです。

かなり長い間検索してきましたが、正しい検索用語を思いつくことができないか、JBoss 4.x と JBoss 7 の MBean 定義の間のギャップを埋めるための知識が不足しています。

したがって、誰かが私が見逃している可能性があるものや、どこで読む必要があるかについてのヒントを提供できることを願っています (おそらくいくつかのドキュメント、例など)。

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 はこれらの mbean を自動的に登録します。

どうやら、JBoss 7 では@Serviceアノテーションが存在しないため、別のアプローチが必要です。

これまでのところ、MBean を手動でプラットフォーム mbean サーバーに登録することができましたが、JBoss に自動的に登録してもらいたいと考えています。さらに、これまでのところ、メソッド/パラメーターの説明を提供することができませんでした (これらは、あると便利な機能ですが)。

明確にするために、質問を繰り返します。

次の機能を提供する JBoss 7 (Java EE 6) で MBean を定義するにはどうすればよいですか?

  • 自動展開
  • EJB へのアクセス
  • JConsole または JMX-Console からアクセス可能 (私は現在 Dimitris Andreadis のポートを使用しています)
  • メソッド/パラメーターの説明を提供する

アップデート

これが私がこれまでに得たものです:

最初に、CDI を使用して任意の Bean のインジェクション ターゲットをラップし、それに応じてアノテーションが付けられ、postConstruct()メソッドで JMX 登録を行うこのプロジェクションを見つけました: http://code.google.com/p/jmx-annotations/。さらに、検出された MBean は、注釈付きプロパティの説明を提供するクラス/属性/メソッド/パラメータ注釈についてスキャンされます。

ただし、postConstruct()メソッドはEJBに対して呼び出されないようです(EJBコンテナと衝突しないためだと思います)。したがって、MBean は EJB ではなく、プレーンな CDI Bean にする必要があります。

ただし、MBean が自動的にインスタンス化されないという欠点があります。BeanManagerこれを克服するために、起動時にすべての Bean をループし、見つかったすべての MBean のインスタンスを作成するシングルトン Bean があります。MBean にはまだ注入ターゲットがあるため、そのpostConstruct()メソッドは呼び出されず、Bean は MBean サーバーに登録されます。

起動手順の大まかな概要は次のとおりです。

  • カスタム CDI 拡張機能は、各 CDI Bean をスキャンしてカスタム @MBean アノテーションを探します。
  • 適格な MBean ごとに、注入ターゲットがラップされます
  • @PostConstruct メソッドで MBean のインスタンスを作成する singleton Bean が開始されます
  • MBean のインジェクション ターゲットのpostConstruct()メソッドが呼び出され、MBean が MBean サーバーに登録されます。

このメソッドの欠点の 1 つは、MBean メソッドを実行するときにトランザクション コンテキストが欠落することです (すべての EJB 呼び出しはトランザクション コンテキストで実行されます)。ただし、これは、必要に応じてトランザクション コンテキストを提供する CDI インターセプターを使用して修正できます。Seam プロジェクトには、そのための適切なインターセプターがあるようです。

これが健全で安定したアプローチであるかどうかはまだわからないので、建設的なコメント、ヒントなどは大歓迎です。

4

2 に答える 2

3

@Startupを使用したシングルトンEJB? http://www.adam-bien.com/roller/abien/entry/singleton_the_simplest_possible_jmx

于 2012-07-04T17:09:18.987 に答える
1

それを行うより簡潔な方法は、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

魅力のように動作します)

于 2014-03-14T19:42:07.640 に答える