从 JBoss 4.x 到 JBoss 7 的 Port MBean

2022-09-04 04:37:35

我们目前正在将一些项目从 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";
  }
}

我们使用注释来定义对象名称和 xmbean 描述符,JBoss 会自动注册这些 mbean。@Service

显然,在JBoss 7中,注释不再存在,因此需要另一种方法。@Service

到目前为止,我设法在平台mbean服务器上手动注册了MBAan,但我宁愿JBoss自动执行此操作。此外,到目前为止,我没有设法为方法/参数提供描述(尽管这些功能更好)。

为了清楚起见,我将重复这个问题:

如何在 JBoss 7 (Java EE 6) 中定义提供以下功能的 MBean?

  • 自动部署
  • 访问 EJB
  • 可通过JConsole或JMX-Console访问(我目前正在使用Dimitris Andreadis的端口)
  • 提供方法/参数的描述

更新

以下是我到目前为止所得到的:

首先,我找到了这个投影,它使用CDI来包装任何豆子的注入目标,并相应地注释,并在方法中执行JMX注册:http://code.google.com/p/jmx-annotations/。此外,还会扫描找到的 MBean,以查找为带批注的属性提供说明的类/特性/方法/参数批注。postConstruct()

但是,该方法似乎不是为 EJB 调用的(我假设这是为了不与 EJB 容器冲突)。因此,MBeans现在不应该是EJB,而是普通的CDIbean。postConstruct()

因此,具有MBBean不会自动实例化的缺点。为了克服这一点,有一个单例Bean,它在启动时循环遍历中的所有Bean,并创建找到的每个MBAan的实例。由于 MBean 仍具有其注入目标,因此不会调用其方法,并且 Bean 将在 MBean 服务器中注册。BeanManagerpostConstruct()

以下是启动过程的粗略概述:

  • 自定义 CDI 扩展扫描每个 CDI bean 以查找自定义@MBean注释
  • 对于每个可识别的MBAan,注射目标被包裹
  • 将启动一个单例 bean,在其@PostConstruct方法中将创建 MBean 的实例
  • 将调用 MBean 注入目标的方法,因此 MBean 在 MBean 服务器中注册postConstruct()

此方法的一个缺点是在执行 MBean 方法时缺少事务上下文(任何 EJB 调用都将在事务上下文中运行)。但是,如果需要,可以使用CDI拦截器来解决此问题,该拦截器将提供事务上下文。Seam项目似乎有适当的拦截器。

我仍然不确定这是否是一种理智和稳定的方法,所以任何建设性的评论,提示等都非常欢迎。


答案 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

像吊饰一样工作)


推荐