Abstract Template Beans
Template beans can be extremely useful for defining common configuration settings that you might want to be able to reuse across multiple bean definitions.
An abstract bean definition allows you to specify a "template" that you can use for any beans that you want to apply a common set of configuration settings. In the case of transaction-managed services, if your services use consistent naming patterns (save*, delete*, get*) you can reuse that template across all your services that use the same naming pattern.
So, instead of defining the same transaction manager attributes over and over again on each and every one of your services you can just define an abstract template and then define that template as a parent for each bean definition that you want to wrap with a transaction manager. Makes for more concise bean definitions if you have a lot of services that need to use a transaction manager...
The following example shows how you can define a common transaction manager template for your services that you want to wrap with a transaction:
<!-- This defines a default template for a transaction managed service.
Note the use of the absract attribute which allows us to extend this
definition for our service bean definitions without actually instantiating
a bean that represents this "template". -->
<bean id="txManagerTemplate" abstract="true" depends-on="transactionManager"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<!-- Define the default patterns for methods that require transaction management. -->
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
The use of abstract bean templates aren't just for transaction-managed services either. You can use abstract bean templates for any bean definitions where you want to reuse a common set of configuration settings across multiple bean definitions. If you find yourself defining the same properties over and over again on many different bean definitions, using a bean template can be an easy way to simplify your bean configurations.
Using Inner Beans
Another suggestion mentioned in the "Hibernate Transactions - Part 1 - How to Wrap..." was the use of naming patterns in order to distinguish the actual service implementation from the service that you want to expose as a transaction-managed service.
Another way to define the services is to use an inner bean as the 'target' property for the TansactionFactoryProxyBean instead of a reference to a standalone bean. The benefit that you get from defining a bean in this manner is that if the bean is configured as an inner bean you can't directly reference it because it doesn't have a bean ID. This can help avoid confusion over which bean you're supposed to interact with because now the only bean that's actually available is the one that you've wrapped with the transaction manager.
Below is an example where the actual service implementation is wrapped as an inner bean. This allows only the actual service that you have wrapped with the transaction manager to be exposed as a service bean and prevents someone from inadvertently using the service that doesn't use a transaction manager.
<!-- Define the service but wrap it using the transaction manager template so
operations can be performed transparently with or without a transaction.
Note how this bean definition reuses the common transaction manager template
via the parent attribute on the bean definition. -->
<bean id="ImportKeyDataService" parent="txManagerTemplate">
<property name="target">
<!-- Define as an inner bean here so that we can't directly reference the implementation.
Using an inner bean avoids any confusion about which service bean should actually be used. -->
<bean class="cat.dds.fpsdma.services.ImportKeyDataService">
<constructor-arg index="0" ref="fpsDAO"/>
</bean>
</property>
<!-- You can override the default transaction attributes if necessary.
However, this isn't required if your service uses the same naming
pattern as defined in your parent bean definition. -->
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="write*">PROPAGATION_REQUIRED</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
Very nice! We have piles and piles of duplicate XML in our app. This is great stuff. Thanks!
ReplyDelete