David M. Karr opened SPR-11298 and commented

I needed to write an MBeanExporter subclass that works with the ATG framework, but for the scope of this issue, ATG isn't important. The exporter gets access to a collection of objects that have an implicit "name", and the exporter needs to have JMX MBeans created for all of them.

I wanted to allow for the option of using the Spring @ManagedResource annotation, along with its associated sub-annotations, but if an associated class doesn't have that annotation, it should just use the defaults. In other words, I want it to behave like both "MBeanExporter" and "AnnotationMBeanExporter". If a bean it's processing has the annotation, it should act like the latter, otherwise the former.

Out of the box, if I process my bean collection with "AnnotationMBeanExporter", then it will require that all of the associated classes have the "@ManagedResource" annotation. If a single class in the list doesn't have it, the process fails. If I instead use the plain "MBeanExporter", I only get default processing for all beans. If an associated class has the annotation with additional metadata, it will be ignored.

I was able to work around this by simply instantiating both a "MBeanExporter" and a "AnnotationMBeanExporter", and controlling the list of beans provided to each of them, making sure that only beans with classes with the annotation were provided to the latter, and all others to the former.

That's not very convenient. It would be much better if I could define a single MBeanExporter that would use the annotations if present, and use the default strategy if not.

I asked about this on StackOverflow (http://stackoverflow.com/questions/20672671/how-to-make-custom-spring-mbeanexporter-use-the-managed-annotations-on-a-can?noredirect=1#comment30990785_20672671), and with the help of Martin Deinum, I was able to build a component that does exactly this. I had to do a couple of sub-optimal things in this implementation, because I needed to be able to call methods in existing Spring classes, without having to do copy/paste reuse. In most cases, I was able to achieve that, with at least one exception. If this code was integrated into Spring, someone would have the ability to refactor this better to avoid copying code.

I'm attaching the three classes I wrote for this implementation (exporter, strategy, and assembler).

I'm also attaching the ATG-specific subclass that I wrote, NucleusMBeanExporter. I'm only attaching this for an illustration of how I'm extending my implementation. I don't intend for this class to be integrated into Spring.


Affects: 4.0 GA

Reference URL: http://stackoverflow.com/questions/20672671/how-to-make-custom-spring-mbeanexporter-use-the-managed-annotations-on-a-can?noredirect=1#comment30990785_20672671

Attachments: - AnnotationOrDefaultMBeanExporter.java (1.82 kB) - MetadataOrKeyNamingStrategy.java (1.48 kB) - MetadataOrSimpleReflectiveMBeanInfoAssembler.java (4.35 kB) - NucleusMBeanExporter.java (3.67 kB)

Issue Links: - #14541 Allow @ManagedResource to be used with @Bean methods - #18614 Reject @ManagedResource a on class which is not public

1 votes, 3 watchers

Comment From: jhoeller

Since this has not turned out as a common scenario and can be accomplished through custom strategies, we have no plans to revise the out-of-the-box strategy offering. FWIW there is a key-based fallback in MetadataNamingStrategy already (just without configurable mapping options), and there is also the autodetection of common MBean types in the application context.