讓Spring架構減化事務配置
注:原創文章,本文曾發表于it168
Spring顛覆了以前的編程模式,引入了IOC等全新的概念,廣受大家的喜愛。目前大多數j2ee項目都已經采用Spring框架。Spring最大的問題是太多的配置文件,使得你不僅需要維護程序代碼,還需要額外去維護相關的配置文件。最典型的就是事務配置(注:這里的“事務配置”都指“聲明式事務配置”),在Spring中進行事務配置除了定義對象自身的bean外,還需要定義一個進行事務代理的bean.如果你有n個類需要引入事務,那么你就必須定義2n個bean。維護這些bean的代價是十分昂貴的,所以必須要對事務配置進行減化。如果你是基于Spring進行架構設計,那么作為一個好的架構設計師,應該把一些公共的方面進行簡化,讓項目的開發人員只關心項目的業務邏輯,而不要花費太多的精力去關心業務邏輯之外的太多東西。所以作為一個好的架構就應該把事務管理進行簡化,讓程序員花在編程之外的工作最小化。
1. Spring聲明式事務配置的幾種方法
在Spring中進行事務控制首先要選擇適當的事務管理器,其次為程序選擇劃分事務的策略。如果只有單個事務性資源,可以從“單一資源”的PlatformTransactionManger實現當中選擇一個,這些實現有:DataSourceTransactionManager,HibernateTransactionManager, JdoTransactionManager,PersistenceBrokerTransactionManager和JmsTransactionManager。根據你所采用的數據庫持久化技術選擇。如果你的項目運行于支持JTA的服務器,那么將選擇JtaTransactionManger,將會支持多資源事務。
下表將為你選擇適當的事務管理器提供參考。
技術 事務管理器 內建的事務支持
JDBC DataSurceTransactionManagerJtaTransactionManager JdbcTemplate和org.springframework.jdbc.object包中的所有類
IBATIS DataSourceTransactionManagerJtaTransactionManager SqlMapClientTemplate和SqlClientTemplate
Hibernate HibernateTransactionManagerJtaTransactionManager HibernateTemplate和HibernateInterceptor
JDO JdoTransactionManagerJtaTransactionManager JdoTemplate和JdoInterceptor
ApacheOJB PersistenceBrokerTransactionManagerJtaTransactionManager PersistenceBrokerTemplate
JMS JmsTransactionManager JmsTemplate
在劃分事務時,我們需要進行事務定義,也就是配置事務的屬性。事務的屬性有傳播行業,隔離級別,超時值及只讀標志。TransactionAttribute接口指定哪些異常將導致一個回滾,哪些應該一次性提交。
(1) 使用ProxyFactoryBean 和TransactionInterceptor
<!--定義本地數據源-->
<bean id="dataSource" name="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- !定義單個jdbc數據源的事務管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!—定義攔截器-->
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="find*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
</props>
</property>
</bean>
<!—定義業務對象-->
<bean id="com.prs.application.ehld.sample.biz.service.sampleService.target"
class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl">
<property name="userInfoDAO"
ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO">
</property>
</bean>
<!—定義業務對象的事務代理對象-->
<bean id="com.prs.application.ehld.sample.biz.service.sampleService" class="org.springframeword.aop.framework.ProxyFacgtoryBean">
<property name="target"
ref="com.prs.application.ehld.sample.biz.service.sampleService.target">
</property>
<property name="interceptorNames">
<value>transactionInterceptor</value>
</property>
</bean>
通過ProxyFacgtoryBean和TransactionInterceptor組合使用,可以對事務進行更多的控制。所有需要事務控制的對象可以共享一個transactionInterceptor的事務屬性。
(2) 使用TransactionProxyFactoryBean
<!—定義業務對象-->
<bean id="com.prs.application.ehld.sample.biz.service.sampleService.target"
class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl">
<property name="userInfoDAO"
ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO">
</property>
</bean>
<!—定義業務對象的事務代理對象-->
<bean id="com.prs.application.ehld.sample.biz.service.sampleService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
abstract="true">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="target"
ref="com.prs.application.ehld.sample.biz.service.sampleService.target" />
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="find*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
</props>
</property>
</bean>
使用TransactionProxyFactoryBean需要為每一個代理對象都去定義自己的事務屬性。
(3) 使用TransactionProxyFactoryBean及abstract屬性來簡化配置
這種方工也是目前使用得最多的一種聲明式事務配置方法
<!--事務控制代理抽象定義 -->
<bean id="baseTransactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
abstract="true">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="find*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
</props>
</property>
</bean>
<!—定義業務對象-->
<bean id="com.prs.application.ehld.sample.biz.service.sampleService.target"
class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl">
<property name="userInfoDAO"
ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO">
</property>
</bean>
<!—定義業務對象的事務代理對象-->
<bean id="com.prs.application.ehld.sample.biz.service.sampleService" parent="baseTransactionProxy">
<property name="target"
ref="com.prs.application.ehld.sample.biz.service.sampleService.target">
</property>
</bean>
使用abstract屬性,可以讓代理對象可以共享一個定義好的事務屬性,使配置簡化。
(4)使用BeanNameAutoProxyCreator
<!—定義攔截器-->
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="find*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
</props>
</property>
</bean>
<!—定義bean別名自動代理創建器-->
<bean id="autoProxyCreator"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="interceptorNames">
<value>transactionInterceptor</value>
</property>
<property name="beanNames">
<list>
<idref local="com.prs.application.ehld.sample.biz.service.sampleService"/>
</list>
</property>
</bean>
<!—定義業務對象-->
<bean id="com.prs.application.ehld.sample.biz.service.sampleService"
class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl">
<property name="userInfoDAO"
ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO">
</property>
</bean>
使用BeanNameAutoProxyCreator可以由框架來提供適當的代理,由一個transactionInterceptor統一定義事務屬性,只需要把需要事務控制的bean加到beannames的列表。
對于需要大量聲明式事務的bean,BeanNameAutoProxyCreator是十分方便的。減少了代理bean的定義,還可以靈活的決定一個bean是否進行事務控制。
上面四種方法是在Spring中常見的聲明式事務配置方法,其中使用TransactionProxyFactoryBean及abstract屬性進行配置是最常見的簡化方法。
http://www.iteye.com/topic/72435
注:原創文章,本文曾發表于it168
Spring顛覆了以前的編程模式,引入了IOC等全新的概念,廣受大家的喜愛。目前大多數j2ee項目都已經采用Spring框架。Spring最大的問題是太多的配置文件,使得你不僅需要維護程序代碼,還需要額外去維護相關的配置文件。最典型的就是事務配置(注:這里的“事務配置”都指“聲明式事務配置”),在Spring中進行事務配置除了定義對象自身的bean外,還需要定義一個進行事務代理的bean.如果你有n個類需要引入事務,那么你就必須定義2n個bean。維護這些bean的代價是十分昂貴的,所以必須要對事務配置進行減化。如果你是基于Spring進行架構設計,那么作為一個好的架構設計師,應該把一些公共的方面進行簡化,讓項目的開發人員只關心項目的業務邏輯,而不要花費太多的精力去關心業務邏輯之外的太多東西。所以作為一個好的架構就應該把事務管理進行簡化,讓程序員花在編程之外的工作最小化。
1. Spring聲明式事務配置的幾種方法
在Spring中進行事務控制首先要選擇適當的事務管理器,其次為程序選擇劃分事務的策略。如果只有單個事務性資源,可以從“單一資源”的PlatformTransactionManger實現當中選擇一個,這些實現有:DataSourceTransactionManager,HibernateTransactionManager, JdoTransactionManager,PersistenceBrokerTransactionManager和JmsTransactionManager。根據你所采用的數據庫持久化技術選擇。如果你的項目運行于支持JTA的服務器,那么將選擇JtaTransactionManger,將會支持多資源事務。
下表將為你選擇適當的事務管理器提供參考。
技術 事務管理器 內建的事務支持
JDBC DataSurceTransactionManagerJtaTransactionManager JdbcTemplate和org.springframework.jdbc.object包中的所有類
IBATIS DataSourceTransactionManagerJtaTransactionManager SqlMapClientTemplate和SqlClientTemplate
Hibernate HibernateTransactionManagerJtaTransactionManager HibernateTemplate和HibernateInterceptor
JDO JdoTransactionManagerJtaTransactionManager JdoTemplate和JdoInterceptor
ApacheOJB PersistenceBrokerTransactionManagerJtaTransactionManager PersistenceBrokerTemplate
JMS JmsTransactionManager JmsTemplate
在劃分事務時,我們需要進行事務定義,也就是配置事務的屬性。事務的屬性有傳播行業,隔離級別,超時值及只讀標志。TransactionAttribute接口指定哪些異常將導致一個回滾,哪些應該一次性提交。
(1) 使用ProxyFactoryBean 和TransactionInterceptor
<!--定義本地數據源-->
<bean id="dataSource" name="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- !定義單個jdbc數據源的事務管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!—定義攔截器-->
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="find*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
</props>
</property>
</bean>
<!—定義業務對象-->
<bean id="com.prs.application.ehld.sample.biz.service.sampleService.target"
class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl">
<property name="userInfoDAO"
ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO">
</property>
</bean>
<!—定義業務對象的事務代理對象-->
<bean id="com.prs.application.ehld.sample.biz.service.sampleService" class="org.springframeword.aop.framework.ProxyFacgtoryBean">
<property name="target"
ref="com.prs.application.ehld.sample.biz.service.sampleService.target">
</property>
<property name="interceptorNames">
<value>transactionInterceptor</value>
</property>
</bean>
通過ProxyFacgtoryBean和TransactionInterceptor組合使用,可以對事務進行更多的控制。所有需要事務控制的對象可以共享一個transactionInterceptor的事務屬性。
(2) 使用TransactionProxyFactoryBean
<!—定義業務對象-->
<bean id="com.prs.application.ehld.sample.biz.service.sampleService.target"
class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl">
<property name="userInfoDAO"
ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO">
</property>
</bean>
<!—定義業務對象的事務代理對象-->
<bean id="com.prs.application.ehld.sample.biz.service.sampleService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
abstract="true">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="target"
ref="com.prs.application.ehld.sample.biz.service.sampleService.target" />
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="find*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
</props>
</property>
</bean>
使用TransactionProxyFactoryBean需要為每一個代理對象都去定義自己的事務屬性。
(3) 使用TransactionProxyFactoryBean及abstract屬性來簡化配置
這種方工也是目前使用得最多的一種聲明式事務配置方法
<!--事務控制代理抽象定義 -->
<bean id="baseTransactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
abstract="true">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="find*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
</props>
</property>
</bean>
<!—定義業務對象-->
<bean id="com.prs.application.ehld.sample.biz.service.sampleService.target"
class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl">
<property name="userInfoDAO"
ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO">
</property>
</bean>
<!—定義業務對象的事務代理對象-->
<bean id="com.prs.application.ehld.sample.biz.service.sampleService" parent="baseTransactionProxy">
<property name="target"
ref="com.prs.application.ehld.sample.biz.service.sampleService.target">
</property>
</bean>
使用abstract屬性,可以讓代理對象可以共享一個定義好的事務屬性,使配置簡化。
(4)使用BeanNameAutoProxyCreator
<!—定義攔截器-->
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="find*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
</props>
</property>
</bean>
<!—定義bean別名自動代理創建器-->
<bean id="autoProxyCreator"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="interceptorNames">
<value>transactionInterceptor</value>
</property>
<property name="beanNames">
<list>
<idref local="com.prs.application.ehld.sample.biz.service.sampleService"/>
</list>
</property>
</bean>
<!—定義業務對象-->
<bean id="com.prs.application.ehld.sample.biz.service.sampleService"
class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl">
<property name="userInfoDAO"
ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO">
</property>
</bean>
使用BeanNameAutoProxyCreator可以由框架來提供適當的代理,由一個transactionInterceptor統一定義事務屬性,只需要把需要事務控制的bean加到beannames的列表。
對于需要大量聲明式事務的bean,BeanNameAutoProxyCreator是十分方便的。減少了代理bean的定義,還可以靈活的決定一個bean是否進行事務控制。
上面四種方法是在Spring中常見的聲明式事務配置方法,其中使用TransactionProxyFactoryBean及abstract屬性進行配置是最常見的簡化方法。
http://www.iteye.com/topic/72435