Spring事务处理时自我调用的解决方案及一些实现方式的风险
?
前些日子一朋友在需要在目标对象中进行自我调用,且需要实施相应的事务定义,且网上的一种通过BeanPostProcessor的解决方案是存在问题的。因此专门写此篇帖子分析why。
1、预备知识aop概念请参考【http://www.iteye.com/topic/1122401】和【http://jinnianshilongnian.iteye.com/blog/1418596】
spring的事务管理,请参考【http://jinnianshilongnian.iteye.com/blog/1441271】
public interface AService { public void a(); public void b();} @Service()public class AServiceImpl1 implements AService{ @Transactional(propagation = Propagation.REQUIRED) public void a() { this.b(); } @Transactional(propagation = Propagation.REQUIRES_NEW) public void b() { }}
?
3、问题
?
public void a() {aopProxy.b();//即调用AOP代理对象的b方法即可执行事务切面进行事务增强}?
<aop:aspectj-autoproxy expose-proxy="true"/><!—注解风格支持-->
<aop:config expose-proxy="true"><!—xml风格支持-->?
@Servicepublic class AServiceImpl3 implements AService{ @Autowired //① 注入上下文 private ApplicationContext context; private AService proxySelf; //② 表示代理对象,不是目标对象 @PostConstruct //③ 初始化方法 private void setSelf() { //从上下文获取代理对象(如果通过proxtSelf=this是不对的,this是目标对象) //此种方法不适合于prototype Bean,因为每次getBean返回一个新的Bean proxySelf = context.getBean(AService.class); } @Transactional(propagation = Propagation.REQUIRED) public void a() { proxySelf.b(); //④ 调用代理对象的方法 这样可以执行事务切面 } @Transactional(propagation = Propagation.REQUIRES_NEW) public void b() { }}?
public interface BeanSelfAware { void setSelf(Object proxyBean);}
?即我们自定义的BeanPostProcessor?(InjectBeanSelfProcessor)如果发现我们的Bean是实现了该标识接口就调用setSelf注入代理对象。
@Servicepublic class AServiceImpl4 implements AService, BeanSelfAware {//此处省略接口定义 private AService proxySelf; public void setSelf(Object proxyBean) { //通过InjectBeanSelfProcessor注入自己(目标对象)的AOP代理对象 this.proxySelf = (AService) proxyBean; } @Transactional(propagation = Propagation.REQUIRED) public void a() { proxySelf.b();//调用代理对象的方法 这样可以执行事务切面 } @Transactional(propagation = Propagation.REQUIRES_NEW) public void b() { }}?
@Componentpublic class InjectBeanSelfProcessor implements BeanPostProcessor { public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if(bean instanceof BeanSelfAware) {//如果Bean实现了BeanSelfAware标识接口,就将代理对象注入 ((BeanSelfAware) bean).setSelf(bean); //即使是prototype Bean也可以使用此种方式 } return bean; }}?
@Servicepublic class AServiceImpl implements AService, BeanSelfAware {//此处省略Aservice接口定义 @Autowired private BService bService; //① 通过@Autowired方式注入BService private AService self; //② 注入自己的AOP代理对象 public void setSelf(Object proxyBean) { this.self = (AService) proxyBean; //③ 通过InjectBeanSelfProcessor注入自己(目标对象)的AOP代理对象 System.out.println("AService=="+ AopUtils.isAopProxy(this.self)); //如果输出true标识AOP代理对象注入成功 } @Transactional(propagation = Propagation.REQUIRED) public void a() { self.b(); } @Transactional(propagation = Propagation.REQUIRES_NEW) public void b() { }}
??
@Servicepublic class BServiceImpl implements BService, BeanSelfAware {//此处省略Aservice接口定义 @Autowired private AService aService; //① 通过@Autowired方式注入AService private BService self; //② 注入自己的AOP代理对象 public void setSelf(Object proxyBean) { //③ 通过InjectBeanSelfProcessor注入自己(目标对象)的AOP代理对象 this.self = (BService) proxyBean; System.out.println("BService=" + AopUtils.isAopProxy(this.self)); //如果输出true标识AOP代理对象注入成功 } @Transactional(propagation = Propagation.REQUIRED) public void a() { self.b(); } @Transactional(propagation = Propagation.REQUIRES_NEW) public void b() { }}
@RunWith(value = SpringJUnit4ClassRunner.class)@ContextConfiguration(value = {"classpath:spring-config.xml"})public class SelfInjectTest { @Autowired AService aService; @Autowired BService bService; @Test public void test() { }}??
?
@Componentpublic class InjectBeanSelfProcessor2 implements BeanPostProcessor, ApplicationContextAware { private ApplicationContext context; //① 注入ApplicationContext public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.context = applicationContext; } public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if(!(bean instanceof BeanSelfAware)) { //② 如果Bean没有实现BeanSelfAware标识接口 跳过 return bean; } if(AopUtils.isAopProxy(bean)) { //③ 如果当前对象是AOP代理对象,直接注入 ((BeanSelfAware) bean).setSelf(bean); } else { //④ 如果当前对象不是AOP代理,则通过context.getBean(beanName)获取代理对象并注入 //此种方式不适合解决prototype Bean的代理对象注入 ((BeanSelfAware)bean).setSelf(context.getBean(beanName)); } return bean; } public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; }}
?
5、总结纵观其上:
【3.1?通过ThreadLocal暴露Aop代理对象】适合解决所有场景(不管是singleton Bean还是prototype Bean)的AOP代理获取问题(即能解决目标对象的自我调用问题);
?
【3.2?通过初始化方法在目标对象中注入代理对象】?和【3.4?改进版的InjectBeanSelfProcessor的解决方案】能解决普通(无循环依赖)的AOP代理对象注入问题,而且也能解决【3.3】中提到的循环依赖(应该是singleton之间的循环依赖)造成的目标对象无法注入AOP代理对象问题,但该解决方案不适合解决循环依赖中包含prototype Bean的自我调用问题;
?
【3.3?通过BeanPostProcessor?在目标对象中注入代理对象】:只能解决?普通(无循环依赖)的?的Bean注入AOP代理,无法解决循环依赖的AOP代理对象注入问题,即无法解决目标对象的自我调用问题。
?
没有完美的解决方案,只有最适用的解决方案。
?
测试代码请参考附件,jar包与http://www.iteye.com/topic/1120924使用的是一样的