Spring提供了两种事物管理的方法:声明式事务管理和编程式事务管理。
其中声明式事务管理是通过Spring AOP实现,能达到最少影响应用的代码,这是和非侵入性的轻量级容器的观念是一致的。大致总结一下声明事务的方法如下:
(1)使用AOP ProxyFactoryBean和TransactionIntercepter
使用ProxyFactoryBean和TransactionIntercepter步骤
1.定义数据源,事务管理类
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName"> <value>org.postgresql.Driver</value></property> <property name="url"> <value>jdbc:postgresql://localhost/prospring</value></property> <property name="username"><value>janm</value></property> <property name="password"><value>****</value></property> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource"><ref local="dataSource"/></property> </bean> |
2.定义事务拦截器,such as:
(2)使用TransactionProxyFactoryBean
使用TransactionProxyFactoryBean:
1.事务管理类
<bean id="userManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager"><ref bean="transactionManager"/></property> <property name="target"><ref local="userManagerTarget"/></property> <property name="transactionAttributes"> <props> <prop key="insert*">PROPAGATION_REQUIRED</prop> <prop key="update*">PROPAGATION_REQUIRED</prop> <prop key="*">PROPAGATION_REQUIRED,readOnly</prop> </props> </property> </bean> |
TransactionProxyFactoryBean只是为组件的事务代理,如果我们要给组件添加一些业务方面的验证等,可以使用TransactionTemplate加拦截器方式,为组件添加多个拦截器,spring AOP中提供了三类Advice,即前增强,后增强,抛出异常时的增强,可以灵活使用。
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager"/> |
2.定义事务代理
(3)代码级元数据声明方法:
(4)BeanNameAutoProxyCreator,另一种声明方式
TransactionProxyFactoryBean非常有用,当事 务代理包装对象时,它使你可以完全控制代理。如果你需要用一致的方式(例如,一个 样板文件,“使所有的方法事务化”)包装大量的bean,使用一个 BeanFactoryPostProcessor的一个实现, BeanNameAutoProxyCreator,可以提供另外一种方法, 这个方法在这种简单的情况下更加简单。
重述一下,一旦ApplicationContext读完它的初始化信息,它将初始化所有实 现BeanPostProcessor接口的bean,并且让它们后处理 ApplicationContext中所有其他的bean。所以使用这种机制,一个正 确配置的BeanNameAutoProxyCreator可以用来后处 理所有ApplicationContext中所有其他的bean(通过名称来识别),并且把它 们用事务代理包装起来。真正生成的事务代理和使用 TransactionProxyFactoryBean生成的基本一致,这里不再 讨论。
让我们看下面的配置示例:
<!-- Transaction Interceptor set up to do PROPOGATION_REQUIRED on all methods --> <bean id="matchAllWithPropReq" class="org.springframework.transaction.interceptor.MatchAlwaysTransactionAttributeSource"> <property name="transactionAttribute"><value>PROPAGATION_REQUIRED</value></property> </bean> <bean id="matchAllTxInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> <property name="transactionManager"><ref bean="transactionManager"/></property> <property name="transactionAttributeSource"><ref bean="matchAllWithPropReq"/></property> </bean> <!-- One BeanNameAutoProxyCreator handles all beans where we want all methods to use PROPOGATION_REQUIRED --> <bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="interceptorNames"> <list> <idref local="matchAllTxInterceptor"/> <idref bean="hibInterceptor"/> </list> </property> <property name="beanNames"> <list> <idref local="core-services-applicationControllerSevice"/> <idref local="core-services-deviceService"/> <idref local="core-services-authenticationService"/> <idref local="core-services-packagingMessageHandler"/> <idref local="core-services-sendEmail"/> <idref local="core-services-userService"/> </list> </property> </bean> |
假设我们在ApplicationContext中已经有一个TransactionManager的实例 ,我们首先要做的使创建一个 TransactionInterceptor实例。 根据通过属性传递的TransactionAttributeSource接口的一个实现, ransactionInterceptor决定哪个 方法被拦截。这个例子中,我们希望处理匹配 所有方法这种最简单的情况。这个不是最有效的方式,但设置非常迅速,因为 我可以使用预先定义的匹配所有方法的 MatchAlwaysTransactionAttributeSource类。如果我 们需要特定的方式,可以使用 MethodMapTransactionAttributeSource, NameMatchTransactionAttributeSource或 AttributesTransactionAttributeSource。
现在我们已经有了事务拦截器,我们只需把它交给我们定义的 BeanNameAutoProxyCreator实例中,这样AppliactonContext中 定义的6个bean以同样的方式被封装。你可以看到,这 比用TransactionProxyFactoryBean以一种方式单独封装6个bean简洁很 多。封装第7个bean只需添加一行配置。
你也许注意到可以应用多个拦截器。在这个例子中,我们还应用了一个 前面定义的HibernateInterceptor (bean id=hibInterceptor),它为我们管理 Hibernare的会话。
有一件事值得注意,就是在TransactionProxyFactoryBean, 和BeanNameAutoProxyCreator切换时bean的命名。 第一种情况,你只需给你想要包装的bean一个类似myServiceTarget的id, 给代理对象一个类似myService的id,然后所有代理对象的用户只需引用代理对象, 如myService(这些是通用命名规范, 要点是目标对象要有和代理对象不同的名称,并且它们都要在ApplicationContext中可用)。然而, 使用BeanNameAutoProxyCreator时, 你得命名目标对象为myService。 然后当BeanNameAutoProxyCreator后处理目标对象 并生成代理时,它使得代理以和原始对象的名称被插入到 ApplicationContext中。从这一点看,只有代理(含有被包装的对象)在ApplicationContext中可用。
<bean id = "transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> <property name="transactionManager"><ref bean="transactionManager"/></property> <property name="transactionAttributeSource"> <value> com.test.UserManager.*r=PROPAGATION_REQUIRED </value> </property> </bean> |
3.为组件声明一个代理类:ProxyFactoryBean
<bean id="userManager" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"><value>com.test.UserManager</value></property> <property name="interceptorNames"> <list> <idref local="transactionInterceptor"/> </list> </property> </bean> |