Spring usage guidelines
All new Spring component code should follow these guidelines. If you come across existing code that doesn't follow them, consider refactoring it to do so.
For an overview of how Spring is used in Confluence, see Spring IoC in Confluence.
- Autowiring should only be used for transient, programatically constructed objects like actions and plugins. Never autowire anything that's defined in a config file.
- For singleton components, prefer constructor-based injection with final fields for dependencies.
- Always specify indexes for constructor arguments.
- If you have too many components to fit comfortably in a constructor, that's a sign the design is broken.
- If a component is rarely used (i.e. the upgrade manager), consider giving it prototype scope instead of singleton.
- Avoid circular dependencies. If you see a circular dependency, ask yourself:
- Can this problem be solved using events?
- Can this problem be solved by having one party register a callback?
Why use explicit constructor injection?
- It fails fast. If a dependency is added, removed, missing, renamed, misspelled or the wrong type, you find out with a clear error message during system startup not a NullPointerException much later.
- With the amount of components in our Spring context, the introspection required to perform autowiring (or even to resolve the order of components in a constructor) contributes significantly to the startup time of the application.
- Transactions should be wrapped around the manager layer.
- Use the old-style Spring 1 transaction configuration syntax with explicit proxies - the Spring 2 pointcut syntax seems to slow down container startup (and thus test-running) by a factor of ten
- Managers and DAOs should be wrapped by the profiling interceptor
- If you're wondering whether a bean should be profiled or not, veer towards yes
Could we use some kind of funky XML Spring extension so we could declare a bean like this and have the extension apply the relevant interceptors?
<bean name="blahManager" class="com.example.BlahManager" atl:txn="defaultManagerTxn" atl:profile="yes"/>