Question

Overview
Using

  • Spring 3.0.1 (annotation configuration)
    • Current configuration is using CGLib as proxy creator but this is not my preference
    • Transactions are annotation configured without any special settings
    • All configuration is done with annotations (@Service, @Transactional, @ManagedResource, @Inject, etc.)
  • Hibernate 3.5 (entities are annotated with javax.persistence)

Guidelines highlights

  • Every bean annotated with @Repository or @Service must have an interface
  • Constructor DI (when re-configuration isn't required)
    • Constructor has default visibility (Foo(Bar bar) {...})
  • Bean fields are final (when re-configuration isn't required)
    • Leads to no default constructor
  • Implementations are default visible with final modifier (final class Foo)

The Problem

  1. CGLib can't proxy final classes
  2. CGLib requires default (empty) constructor
  3. Some services are required to be exposed via JMX
  4. MBean exporter can't work unless proxied by CGLib
  5. Some @Transactional @Services are accessed via facade service which requires more than one service to include in the facade transaction (e.g. Observer service over 2 application components)
  6. Some interfaces have more than one implementation (which currently distinguished by @Qualifier)
  7. Future guideline (or nice to have feature) - each application module will have beanRefContext.xml file to configure its internal application context

When I used to work with XML configuration I was able to enforce all the guidelines I presented above, but when switching to annotations it seems like Spring is misbehaving.
Developers in my group prefer annotation configuration (I seems easier to wire and write new code), but I've noticed all kind of "hacks" they introduce to the code to prevent from dealing with Spring application context failures.

The Question(s)

  1. Are there best practices I should follow when using annotation configuration?
    • When using more than one implementation per interface (trying to reduce the use of @Primary or @Qualifier)
    • When using @Transactional
    • When using @ManagedResource
    • When using a combination of the above
  2. Is there a way of stop working with CGLib, keep the annotation configuration and still be able to export my MBeans with annotations?
  3. What is the suitable implementation for keeping most (preferably, all) of my guidelines?
Was it helpful?

Solution

I came up with the following solution (to questions #2 and #3) to be able to enforce my design guidelines and keep using annotation based configuration:

  • Each dependent project (Maven module) has it's own ApplicationContext
  • Every dependent project application context is defined in beanRefContext.xml
  • These application contexts are loaded in hierarchy using Spring context hierarchy mechanism.
    • This step is actually not fully supported by Spring and requires additional work
  • Since my application is layered, I could disable CGLib on all my modules besides the JMX layer (I can live with it :-) ).

The above steps also enabled me to reduce the execution time of Spring aware tests (every module loaded only a sub-set of beans).

As a practical guideline (for question #1), if an interface has more than one implementation, I place @Primary on the widely used one and other clients, requiring another implementation, wire the bean using @Qualifier.

OTHER TIPS

Answer to point 2) You could use AspectJ instead of CGLib.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top