Cleaner and More Concise Transaction Definitions in Spring 1.1
(Note: this post modified 2004-10-7 to reflect new ‘abstract’ attribute introduced with Spring 1.1.1 released on 2004-9-30).
People typically create transactional proxies for service interfaces in their Spring ApplicationContext definitions using either TransactionProxyFactoryBean or BeanNameAutoProxyCreator. This post details how enhancements for Spring 1.1 (included in the current v1.1RC1) allow defining transactional proxies in a much more concise fashion than previously.
Assuming a transaction manager bean has already been defined in the context, a typical Spring 1.0.x transaction proxy definition might have looked like this:
<!-- the business object to be wrapped --> <bean id="myServiceTarget" class="org.springframework.samples.MyServiceImpl"> </bean> <!-- tx proxy for the service implementation --> <bean id="myService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager"><ref local="transactionManager"/></property> <property name="target"><ref local="myServiceTarget"/></property> <property name="transactionAttributes"> <props> <prop key="*">PROPAGATION_REQUIRED</prop> </props> </property> </bean>
This works fine, but is fairly verbose to do over and over when you have dozens or even a hundred or more proxies that may be needed in a big app. It's potentially even more verbose than this, since you may want to be even more specific about transaction propagation settings:
<props> <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop> <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop> <prop key="load*">PROPAGATION_REQUIRED,readOnly</prop> <prop key="store*">PROPAGATION_REQUIRED</prop> </props>
(just an example, these method signatures are probably more appropriate to DAOs than a service interface).
One solution when most of your proxies will have similar settings, is to use BeanNameAutoProxyCreator, as described in the Spring manual. This works fine, but is only less verbose when almost all the beans are using the same propagation settings. Additionally, BeanNameAutoProxyCreator has no significant performance implications for your typical app with mostly singleton beans inside the appcontext (and you shouldn't be afraid of using it), but since the bean names are regexes, in cases when you are pulling a lot (and I mean a lot) of prototype beans out of it over and over, it’s possible you might even be able to measure some performance implications from using BeanNameAutoProxyCreator. Every bean that gets pulled out has to get checked against the list of name regexes, every time.
Spring 1.1 significantly enhances its support for parent and child bean definitions, as described in the manual. Taking advantage of this, we can now use the approach of having a parent, or template, transaction proxy definition, and then we create each real proxy as a child definition which only has to specify properties that are different from the parent template:
<bean id="txProxyTemplate" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager"><ref local="transactionManager"/></property> <property name="transactionAttributes"> <props> <prop key="*">PROPAGATION_REQUIRED</prop> </props> </property> </bean> <bean id="myServiceTarget" class="org.springframework.samples.MyServiceImpl"> </bean> <bean id="myService" parent="txProxyTemplate"> <property name="target"><ref local="myServiceTarget"/></property> </bean>
But wait, why not also just wrap the target as an inner bean instead? Inner beans have been around a long time, but are little known. This is not much smaller, but even cleaner:
<bean id="txProxyTemplate" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager"><ref local="transactionManager"/></property> <property name="transactionAttributes"> <props> <prop key="*">PROPAGATION_REQUIRED</prop> </props> </property> </bean> <bean id="myService" parent="txProxyTemplate"> <property name="target"> <bean class="org.springframework.samples.MyServiceImpl"> </bean> </property> </bean>
Now when we want to wrap another service, we just add:
<bean id="myOtherService" parent="txProxyTemplate"> <property name="target"> <bean class="org.springframework.samples.MyOtherServiceImpl"> </bean> </property> </bean>
Of course we we can also override the parent definition's transaction propagation settings:
<bean id="mySpecialService" parent="txProxyTemplate"> <property name="target"> <bean class="org.springframework.samples.MySpecialServiceImpl"> </bean> </property> <property name="transactionAttributes"> <props> <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop> <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop> <prop key="load*">PROPAGATION_REQUIRED,readOnly</prop> <prop key="store*">PROPAGATION_REQUIRED</prop> </props> </property> </bean>
Note that this (updated) example marks the parent bean definition with the ‘abstract’ attribute introduced in Spring 1.1.1, set to true, so that the parent bean can never be instantiated. If you are still working with Spring 1.1 for some reason, there is no way to explicitly mark a bean as abstract, but you will want to mark the parent bean definition as ‘lazy-init=”true”‘. This is needed since Spring’s XMLApplicationConext by default pre-instantiates all singleton beans, and setting the definition to lazy-init will stop this. Aside from the new 1.1.1 abstract attribute, the other case where Spring will consider a bean definition as abstract, and not allow a bean to be created, and not try to eagerly pre-instantiate it in the case of a singleton, is if there is no class actually specified for the bean. In that case, the definition obviously has to be considered abstract since it is not complete.


Modified

cbomoo says:
Added on August 3rd, 2004 at 12:08 amGood, thanks colin!!
smccrory says:
Added on August 12th, 2004 at 9:37 amVery, very nice tip!
Colin Sampaleanu says:
Added on September 2nd, 2004 at 7:42 amThanks to whoever posted the param name copy/paste error in TransactionProxyFactoryBean.setPostInterceptors()! I have fixed it. The code itself actually worked fine since the same (bad) param name was used consistently. This sort of thing should normally go in the Spring JIRA bug-tracker.
Davide Baroncelli says:
Added on October 7th, 2004 at 9:13 amIt seems that now spring supports an explicit “abstract” attribute for the bean tag instead of requiring use of “lazy-init”, too, but the 1.1.1 documentation still states the contrary. Note that it seems that one can not define anonymous inner beans with parent definitions, as of now: inner beans with a name and a parent definition seem to be working, though.
Colin Sampaleanu says:
Added on October 7th, 2004 at 9:25 amYes, Juergen added an abstract attribute between 1.1 and 1.1.1. Unfortunately due to an oversight the manual never got updated, although all the samples which use the parent/child idiom do use the new attribute.
Tom Corbin says:
Added on April 21st, 2005 at 5:03 pmIn the latest version all the code’s been munged with html markup.
Ian Lim says:
Added on April 22nd, 2005 at 9:31 pmEr… can the xml example above be reformatted to a cleaner readable one? A bit difficult to figure out
Colin Sampaleanu (blog author) says:
Added on April 22nd, 2005 at 9:41 pmSorry about the formatting snafu. WordPress plugins were interferig with each other. The post should be ok again.
Ali says:
Added on May 2nd, 2005 at 3:16 amHi
but when i use template approch
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED,readOnly
i get the following error.
ERROR:
org.springframework.beans.factory.BeanDefinitionStoreException: Line 55 in XML document from file [/source/WEB-INF/applicationContext.xml] is invalid; nested exception is org.xml.sax.SAXParseException: Attribute “abstract” must be declared for element type “bean”.
i will be very glad if anyone help me
thx
Colin Sampaleanu (blog author) says:
Added on May 3rd, 2005 at 8:09 amAs the first paragraph of this post says, ‘abstract’ was introduced only in Spring 1.1.1. You appear to be using something older. The current production version is 1.1.5, but 1.2RC2 is fine for development.
Pascal says:
Added on June 10th, 2005 at 6:18 pmHello,
I’m getting.
Attribute “abstract” must be declared for element type “bean” error..
I’m using 1.2RC2.
Any help will be greatly appreciated.
Thanks,
Pascal.
Here is a copy of section of applicationContext-service.xml where the error appear.
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED,readOnly
Anonymous says:
Added on June 11th, 2005 at 3:59 pmPascal,
My feeling is that you may think you’re using Spring 1.2RC2, but you’re still picking up a very old DTD from somewhere. The abstract attribute was added for Spring 1.1.1, so I would guess you’re still picking up a 1.1 or earlier DTD.
Ramesh says:
Added on April 16th, 2006 at 10:50 pmImplementing Declarative Transactions must be applied to the Dao’s or at the Service layer? I want to keep my Dao implementations for CRUD operations on the respective Domain Objects. The Service objects will act like Transaction Scripts. In this case where shall I keep the transaction logic. Which place is advisable? As there will be SessionFactory availble in Service objects will the declarative Transactions will work?
Thanks & Regards
Ramesh Mandaleeka
chulls says:
Added on June 26th, 2006 at 12:48 amhi,
can someone provide me with a sample code to use ’setPostInterceptors’ method?
my requirement is to call a aop enabled logging in a method which is in a transaction(declarative) scope.
thanks in advance
fsdfsdfsrfgrAdministrator says:
Added on April 28th, 2007 at 2:13 amwow gold
wow gold