欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

用AOP实现业务service的重新调用(三)

程序员文章站 2022-05-14 19:01:32
...

承接 用AOP实现业务service的重新调用(二),我们继续......

 

代码看似不多,但实现上需要考虑很多问题,因为哪怕只有一个问题没搞定,整个实现就是失败的.

 

问题列表:
1>事务完整性的问题

       前后两次,是否能保证事务的完整性,我们的事务正好也是通过spring的aop实现的,所以要注意我们新加的ServiceRetryAdvice拦截器要在spring事务拦截器之前调用,也就是包在事务拦截器外面,这样才不会影响spring的事务提交/回滚机制.

 

<value>serviceRetryInterceptor</value>
<value>transactionInterceptor</value>

 

 

<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
		<property name="transactionManager"><ref bean="transactionManager"/></property>
		<property name="transactionAttributeSource"><ref bean="txAttribute"/></property>
	</bean>
	
	<bean id="transactionManagerAutoProxy" 
			class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
		<property name="interceptorNames">
			<list>
				<value>serviceRetryInterceptor</value>
				<value>transactionInterceptor</value>
			</list>
		</property>
		<property name="beanNames">
			<list>
				<value>testRootService</value>
				<value>testService</value>
			</list>
		</property>
	</bean>

 

2>事务传播行为PROPAGATION

      通常最简单的情况是一个service方法对应一个事务,按照前面的配置,这种情况是没有问题的,前一次调用失败后,重新调用service,spring会重新开始一个事务,所以新事务会获取一个新的连接,执行成功返回前端.

       

       还有一种情况是service方法里面又调用了子service方法,我们遇到的情况用的是PROPAGATION_REQUIRED(子service方法里面判断当前线程是否存在transaction,如果存在就复用,不存在再创建新transaction),所以这里仅讨论PROPAGATION_REQUIRED的情况,其它情况可以自己去详细考证,如果exception是发生在父service方法里面,没有问题.如果发生在子service方法里面,我们重调的是子service方法,这种情况下retry调用的时候,因为transaction还在,所以继续复用原来的transaction可是transaction里面的connection还是原来的无效连接,所以retry仍然会百分之百失败,所以这种case我们无能为力,直接把异常抛给前端.因为事务的commit/rollback只在父service方法里面进行,所以不会破坏事务的完整性.

 
3>多线程的问题(retryNum)

       为了提高效率,spring内部对interceptor进行了cache,同一个service class+method,会共用同一个interceptor,所以多线程环境下,retryNum成员变量要保证线程安全,解决方法是:我们用了ThreadLocal<Integer>,这样就不用担心多线程访问的问题了.

 

4>ThreadLocal的注意事项

关于ThreadLocal,还需要注意内存泄露的问题,因为ThreadLocal内部对每一个线程都留了一个map,所以我们在使用完以后要主动remove掉里面的内容.

 

} finally {
			retryNum.remove();
}