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.

 

WordPress database error: [Can't open file: 'colins_comments.MYI' (errno: 145)]
SELECT * FROM colins_comments WHERE comment_post_ID = '6' AND comment_approved = '1' ORDER BY comment_date

Leave a Reply