JSR-299 CDI Decorators for Spring beans
Join the DZone community and get the full member experience.
Join For Free This blog is about my new Spring-CDI modules effort. It's pupose is to
make useful CDI patterns like decorators or interceptors available to a
Spring application. I do believe that the explicit pattern
implementation in CDI is very useful. It makes it obvious and simple to
use patterns for not so experienced developers. Therefore I decided to
investigate how to make those patterns and the corresponding CDI
annotations available for Spring managed beans. Here is the current
status of my work. If you're interested and you have some time left,
take a look or try out my early version of the Spring-CDI decorator
module. The set-up is straight forward. You'll find all you need below.
JSR-299 decorator pattern implementation
Features
The decorator module provides the following features:
- Use JSR-299 @Decorator and @Delegate in Spring managed beans
- Support chains of multiple decorators for the same target delegate bean
- Allow to qualify decorators to decorate multiple implementations of the same interface with different decorators
- Support scoped beans, allow scoped decorators
- Integrate with Spring AOP, both dynamic JDK proxies and CGLIB proxies
- Allow definition of custom decorator and delegate annotations
Download Link
The Spring-CDI decorator module is an usual Spring IoC-container extension delivered as JAR archive. You can download the module JAR and put that on the classpath of your Spring application.
Compiled Spring-CDI decorator module JAR: download here
Sources: download here
API-Doc: view here
Everything is hosted on a git repository on Github.com.
Dependencies
Configuration
If the Spring-CDI decorator module JAR and its dependencies are on your classpath, all you need to do is:
(1) register DecoratorAwareBeanFactoryPostProcessor in your application context
(2) define an include-filter to include javax.decorator.Decorator as component annotation in your context:component-scan tag
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd" default-autowire="byName"> <context:component-scan base-package="com.mycompany.springapp.springcdi" scoped-proxy="targetClass"> <context:include-filter type="annotation" expression="javax.decorator.Decorator" /> </context:component-scan> <bean class="com.schlimm.springcdi.decorator.DecoratorAwareBeanFactoryPostProcessor" /> </beans>
Use Case
The following code snippets show how you can use the decorator pattern
ones you have configured your Spring application as described above. For
more complex scenarios see my unit test cases.
Let's assume you have a business interface called: MyService
This is your implementation of the service.
You want to do some transaction and security stuff, but you do not want to mess up the business code with it.
For security you'd write a decorator that points to the MyService business service.
To seperate the cross-cutting-concerns you write another decorator for transaction handling that points to the MyService business service.
Then you can just use standard Spring @Autowired annotation to make that work. The injected bean will be decorated with your new security and transaction decorator.
How it works
The core is the DecoratorAwareBeanFactoryPostProcessor that scans the registered bean definitions for existing decorators. It gathers meta data and stores that data in the DecoratorMetaDataBean. The DecoratorAwareBeanPostProcessor uses the meta data to wire the decorators into a chain and creates a CGLIB proxy that intercepts method calls to the target delegate bean. It redirects those calls to the decorator chain. The DecoratorAutowireCandidateResolver applies autowiring rules specific to the CDI decorator pattern. It also uses meta data to do that.
The two modes
The DecoratorAwareBeanFactoryPostProcessor accepts two runtime modes. The 'processor' (default) mode uses DecoratorAwareBeanPostProcessor and the DecoratorChainingStrategy to wire the decorator chain. The 'resolver' mode uses DecoratorAwareAutowireCandidateResolver to implement custom wiring logic based on complex wiring rules implemented in ResolverCDIAutowiringRules. The 'resolver' mode was just another option how one can implement such complex logic. I tried two different options and both work. The 'processor' alternative however implements simpler logic. Therefore it's my prefered mode at the moment.
Decorator Meta Data Model
The DecoratorAwareBeanFactoryPostProcessor scans bean definitions and stores meta data about the decorators and delegates in the application context. These are the model beans in their hierarchical access order:
DecoratorMetaDataBean.java: Top level entry point to the meta-data. Registered and available in the application context.
QualifiedDecoratorChain.java: A chain of decorators for the same target delegate bean.
DecoratorInfo.java: A decorator bean definition wrapper class.
DelegateField.java: Contains the delegate field of the decorator implementation.
Strategies
The Spring-CDI decorator module is easy to adopt by users through the use of strategy pattern in many places. These are the strategies that allow users to change processing logic if required:
DecoratorChainingStrategy.java: Wires the decorators for a specific target delegate bean.
DecoratorOrderingStrategy.java: Orders the decorators for a specific target delegate bean.
DecoratorResolutionStrategy.java: Scans the bean factory for available decorator beans.
DelegateResolutionStrategy.java: Searches the delegate bean for a specific decorator bean.
Decorator Autowiring Rules
The 'processor' mode and the 'resolver' mode both use a custom AutowireCandidateResolver applied to the current bean factory. The class is called DecoratorAwareAutowireCandidateResolver and it is applied to the bean factory in the DecoratorAwareBeanFactoryPostProcessor. The custom resolver works with different rule sets. In the 'processor' mode it works with a very simple rule set called BeanPostProcessorCDIAutowiringRules. In the 'resolver' mode it uses ResolverCDIAutowiringRules which is far more complex. If these rule sets are not sufficient for your autowiring logic, it's easy to apply additional rule sets by implementing a custom SpringCDIPlugin and adding it to the DecoratorAwareAutowireCandidateResolver.
Spring-CDI Plugin System
The Spring-CDI decorator module contains two infrastructure interfaces that allow the modularized approach of Spring-CDI project: SpringCDIPlugin and SpringCDIInfrastructure. When I implement additional modules - like the interceptor module - users can decide which modules to use and import into their projects. It's not required to add all Spring-CDI functionality if one only needs decorators.
From http://niklasschlimm.blogspot.com/2011/08/jsr-299-cdi-decorators-for-spring-beans.html
Opinions expressed by DZone contributors are their own.
Comments