本文共 10071 字,大约阅读时间需要 33 分钟。
最初使用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需要声明性事务配置的情形。方法二、三配置更加灵活。方法三比方法二更加简洁、紧凑,十分适用于代码生成。另外,方法有个缺点,如果bean实现某些接口,使用方法一无法指定对这些接口进行截获(利用ProxyFactoryBean的proxyInterfaces属性),从而无法使用JDK的动态代理,只能使用CGLIB来实现方法截获。 转载于:https://my.oschina.net/wangjian95/blog/37774