we\'re currently in the process of porting some of our projects from JBoss 4.x to JBoss 7. So far everything seems to work fine, except for our MBeans, which we\'re commonly usi
Singleton EJB with @Startup? http://www.adam-bien.com/roller/abien/entry/singleton_the_simplest_possible_jmx
I think more concise way to do it is to use CDI extension. Please take a look at the solution we use:
@Documented
@Retention(value=RUNTIME)
@Target(value=TYPE)
@Inherited
public @interface MBean {
String value() default "";
}
...
This is working code of CDI extension:
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);
}
}
}
Then just mark your class by @Mbean annotation and will be automatically registered in Mbean server :
@Startup
@Singleton
@MBean("com.company=JmxBindName")
public class SomeService
Works like a charm )