Spring聲明性事務配置幾種方式

 最初使用Spring是爲了解決業務層的事務管理問題。原先用手寫代碼發起、結束/回滾事務的作法碰到粗心的開發者很容易致使鏈接池的資源耗盡。Spring的聲明性事務管理功能無疑是一劑良方。本文說明幾種常見的配置方式及各自的優缺點。
方法一:BeanNameAutoProxyCreator
優勢:有大量bean聲明性事務管理時使用該方法能夠簡化配置
示例:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"
>

<beans>

    <description>
        Exploring spring Dependency Injection feature
    </description>
    <bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
        <property name="configLocation">
            <value>hibernate.cfg.xml</value>
        </property>
    </bean>
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate.HibernateTransactionManager">
        <property name="sessionFactory">
            <ref local="sessionFactory"/>
        </property>
    </bean>

    <!-- Transaction Interceptor set up to do PROPOGATION_REQUIRED on all methods -->
    <bean id="matchAllTxInterceptor"
        class="org.springframework.transaction.interceptor.TransactionInterceptor">
        <property name="transactionManager">
            <ref bean="transactionManager"/>
        </property>
        <property name="transactionAttributes">
            <props>
                <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
                <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
                <prop key="*">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
    </bean>
    <!-- One BeanNameAutoProxyCreator handles all beans where we want all methods to use
    PROPOGATION_REQUIRED -->

    <bean id="hibInterceptor"
        class="org.springframework.orm.hibernate.HibernateInterceptor">
        <property name="sessionFactory">
            <ref bean="sessionFactory"/>
        </property>
    </bean>

    <bean id="autoProxyCreator"
        class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="interceptorNames">
            <list>
                <idref local="matchAllTxInterceptor"/>
                <idref bean="hibInterceptor"/>
            </list>
        </property>
        <property name="proxyTargetClass">
            <value>true</value>
        </property>
        <property name="beanNames">
            <list>
                <value>userDocumentManager</value>
            </list>
        </property>
    </bean>

    <bean id="docServerConfig" class="just.docserver.config.DocServerConfig" singleton="true">
        <property name="config"><value>docsrv.conf</value></property>
        <!-- contextPath is which url path the document server resides, KEEP it sync with actual deployment -->
        <property name="contextPath"><value>/axis</value></property>
    </bean>    
    <!--DAO classes definition begin-->
    <bean id="docDao" class="just.docserver.dal.daoimpl.doc.DocDaoImpl">
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
    </bean>    
    <bean id="userFileDao" class="just.docserver.dal.daoimpl.doc.UserFileDaoImpl">
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
    </bean>    
    <bean id="docSettingDao" class="just.docserver.dal.daoimpl.doc.DocSettingDaoImpl">
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
    </bean>    
    <bean id="userDocumentDao" class="just.docserver.dal.daoimpl.doc.UserDocumentDaoImpl">
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
        <property name="docDao"><ref local="docDao"/></property>
        <property name="docSettingDao"><ref local="docSettingDao"/></property>
        <property name="userFileDao"><ref local="userFileDao"/></property>
    </bean>    
    <!--DAO classes definition end-->
    

    <!--  Service definition begin -->
    <bean id="userDocumentManager"
        class="just.docserver.UserDocumentManagerImpl"
        singleton="true">
        <property name="docDao"><ref local="docDao"/></property>
        <property name="docSettingDao"><ref local="docSettingDao"/></property>
        <property name="userDocumentDao"><ref local="userDocumentDao"/></property>
        <property name="userFileDao"><ref local="userFileDao"/></property>
        <property name="docServerConfig"><ref local="docServerConfig"/></property>
    </bean>
    <!--  Service definition end -->
</beans>
方法二:TransactionProxyFactoryBean
優勢:配置靈活
示例:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"
>

<beans>

    <description>
        Exploring spring Dependency Injection feature
    </description>
    <bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
        <property name="configLocation">
            <value>hibernate.cfg.xml</value>
        </property>
    </bean>
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate.HibernateTransactionManager">
        <property name="sessionFactory">
            <ref local="sessionFactory"/>
        </property>
    </bean>

    <bean id="docServerConfig" class="just.docserver.config.DocServerConfig" singleton="true">
        <property name="config"><value>docsrv.conf</value></property>
        <!-- contextPath is which url path the document server resides, KEEP it sync with actual deployment -->
        <property name="contextPath"><value>/axis</value></property>
    </bean>    
    <!--DAO classes definition begin-->
    <bean id="docDao" class="just.docserver.dal.daoimpl.doc.DocDaoImpl">
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
    </bean>    
    <bean id="userFileDao" class="just.docserver.dal.daoimpl.doc.UserFileDaoImpl">
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
    </bean>    
    <bean id="docSettingDao" class="just.docserver.dal.daoimpl.doc.DocSettingDaoImpl">
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
    </bean>    
    <bean id="userDocumentDao" class="just.docserver.dal.daoimpl.doc.UserDocumentDaoImpl">
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
        <property name="docDao"><ref local="docDao"/></property>
        <property name="docSettingDao"><ref local="docSettingDao"/></property>
        <property name="userFileDao"><ref local="userFileDao"/></property>
    </bean>    
    <!--DAO classes definition end-->
    
    <!--  Service definition begin -->
  <bean id="userDocumentManagerTarget" class="just.docserver.UserDocumentManagerImpl">
      <property name="docDao"><ref local="docDao"/></property>
      <property name="docSettingDao"><ref local="docSettingDao"/></property>
      <property name="userDocumentDao"><ref local="userDocumentDao"/></property>
      <property name="userFileDao"><ref local="userFileDao"/></property>
      <property name="docServerConfig"><ref local="docServerConfig"/></property>
  </bean>

    <bean id="userDocumentManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
      <property name="transactionManager">
        <ref local="transactionManager"/>
      </property>  
      <property name="target">
        <ref local="userDocumentManagerTarget"/>
      </property>
      <property name="proxyInterfaces"><value>just.docserver.UserDocumentManager</value></property>
      <property name="transactionAttributes">
        <props>
            <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
            <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
            <prop key="*">PROPAGATION_REQUIRED</prop>
        </props>
      </property>
    </bean>    
    <!--  Service definition end -->
</beans>
但使用該方法配置時須要多配置一個xxxTarget的bean,該bean一般在應用用沒有直接的用途,使得配置顯得比較累贅。這一問題在高版本的spring中能夠用嵌套的bean來解決。也就是將名爲xxxTarget的bean直接寫道被引用到的地方。按此方法,上例能夠改爲:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"
>

<beans>

    <description>
        Exploring spring Dependency Injection feature
    </description>
    <bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
        <property name="configLocation">
            <value>hibernate.cfg.xml</value>
        </property>
    </bean>
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate.HibernateTransactionManager">
        <property name="sessionFactory">
            <ref local="sessionFactory"/>
        </property>
    </bean>

    <bean id="docServerConfig" class="just.docserver.config.DocServerConfig" singleton="true">
        <property name="config"><value>docsrv.conf</value></property>
        <!-- contextPath is which url path the document server resides, KEEP it sync with actual deployment -->
        <property name="contextPath"><value>/axis</value></property>
    </bean>    
    <!--DAO classes definition begin-->
    <bean id="docDao" class="just.docserver.dal.daoimpl.doc.DocDaoImpl">
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
    </bean>    
    <bean id="userFileDao" class="just.docserver.dal.daoimpl.doc.UserFileDaoImpl">
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
    </bean>    
    <bean id="docSettingDao" class="just.docserver.dal.daoimpl.doc.DocSettingDaoImpl">
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
    </bean>    
    <bean id="userDocumentDao" class="just.docserver.dal.daoimpl.doc.UserDocumentDaoImpl">
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
        <property name="docDao"><ref local="docDao"/></property>
        <property name="docSettingDao"><ref local="docSettingDao"/></property>
        <property name="userFileDao"><ref local="userFileDao"/></property>
    </bean>    
    <!--DAO classes definition end-->
    
    <!--  Service definition begin -->
    <bean id="userDocumentManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
      <property name="transactionManager">
        <ref local="transactionManager"/>
      </property>  
      <property name="target">
          <bean class="just.docserver.UserDocumentManagerImpl">
              <property name="docDao"><ref local="docDao"/></property>
              <property name="docSettingDao"><ref local="docSettingDao"/></property>
              <property name="userDocumentDao"><ref local="userDocumentDao"/></property>
              <property name="userFileDao"><ref local="userFileDao"/></property>
              <property name="docServerConfig"><ref local="docServerConfig"/></property>
          </bean>
      </property>
      <property name="proxyInterfaces"><value>just.docserver.UserDocumentManager</value></property>
      <property name="transactionAttributes">
        <props>
            <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
            <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
            <prop key="*">PROPAGATION_REQUIRED</prop>
        </props>
      </property>
    </bean>         <!--  Service definition end --> </beans> 這樣整個配置更爲簡潔清晰,並且更適合於代碼生成工具來生成這些配置,進一步提升開發效率。 總結: 本文概括了Spring聲明性事務配置幾種方式,BeanNameAutoProxyCreator,TransactionProxyFactoryBean即TransactionProxyFactoryBean加嵌套式Target bean。方法一適用於有大量bean須要聲明性事務配置的情形。方法2、三配置更加靈活。方法三比方法二更加簡潔、緊湊,十分適用於代碼生成。另外,方法有個缺點,若是bean實現某些接口,使用方法一沒法指定對這些接口進行截獲(利用ProxyFactoryBean的proxyInterfaces屬性),從而沒法使用JDK的動態代理,只能使用CGLIB來實現方法截獲。
相關文章
相關標籤/搜索