前些日子一朋友在须要在目标对象中进行自我调用,且须要实施相应的事务定义,且网上的一种经过BeanPostProcessor的解决方案是存在问题的。所以专门写此篇帖子分析why。javascript
aop概念请参考【http://www.iteye.com/topic/1122401】和【http://jinnianshilongnian.iteye.com/blog/1418596】java
spring的事务管理,请参考【http://jinnianshilongnian.iteye.com/blog/1441271】spring
使用AOP 代理后的方法调用执行流程,如图所示app
也就是说咱们首先调用的是AOP代理对象而不是目标对象,首先执行事务切面,事务切面内部经过TransactionInterceptor环绕加强进行事务的加强,即进入目标方法以前开启事务,退出目标方法时提交/回滚事务。post
目标对象内部的自我调用将没法实施切面中的加强,如图所示性能
此处的this指向目标对象,所以调用this.b()将不会执行b事务切面,即不会执行事务加强,所以b方法的事务定义“@Transactional(propagation = Propagation.REQUIRES_NEW)”将不会实施,即结果是b和a方法的事务定义是同样的,能够从如下日志看出:测试
org.springframework.transaction.annotation.AnnotationTransactionAttributeSource Adding transactional method 'a' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''this
org.springframework.beans.factory.support.DefaultListableBeanFactory Returning cached instance of singleton bean 'txManager'spa
org.springframework.orm.hibernate4.HibernateTransactionManager Creating new transaction with name [com.sishuok.service.impl.AServiceImpl1.a]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; '' -----建立a方法事务hibernate
org.springframework.orm.hibernate4.HibernateTransactionManager Opened new Session …… for Hibernate transaction ---打开Session
……
org.springframework.transaction.support.TransactionSynchronizationManager Initializing transaction synchronization
org.springframework.transaction.interceptor.TransactionInterceptor Getting transaction for [com.sishuok.service.impl.AServiceImpl1.a]
org.springframework.transaction.interceptor.TransactionInterceptor Completing transaction for [com.sishuok.service.impl.AServiceImpl1.a] ----完成a方法事务
org.springframework.orm.hibernate4.HibernateTransactionManager Triggering beforeCommit synchronization
org.springframework.orm.hibernate4.HibernateTransactionManager Triggering beforeCompletion synchronization
org.springframework.orm.hibernate4.HibernateTransactionManager Initiating transaction commit
org.springframework.orm.hibernate4.HibernateTransactionManager Committing Hibernate transaction on Session ……---提交a方法事务
或
org.springframework.orm.hibernate4.HibernateTransactionManager Rolling back Hibernate transaction on Session ……---若是有异常将回滚a方法事务
org.springframework.orm.hibernate4.HibernateTransactionManager Triggering afterCommit synchronization
org.springframework.orm.hibernate4.HibernateTransactionManager Triggering afterCompletion synchronization
org.springframework.transaction.support.TransactionSynchronizationManager Clearing transaction synchronization
……
org.springframework.orm.hibernate4.HibernateTransactionManager Closing Hibernate Session …… after transaction --关闭Session
咱们能够看到事务切面只对a方法进行了事务加强,没有对b方法进行加强。
此处a方法中调用b方法时,只要经过AOP代理调用b方法便可走事务切面,便可以进行事务加强,以下所示:
判断一个Bean是不是AOP代理对象可使用以下三种方法:
AopUtils.isAopProxy(bean) : 是不是代理对象;
AopUtils.isCglibProxy(bean) : 是不是CGLIB方式的代理对象;
AopUtils.isJdkDynamicProxy(bean) : 是不是JDK动态代理方式的代理对象;
1、开启暴露Aop代理到ThreadLocal支持(以下配置方式从spring3开始支持)
2、修改咱们的业务实现类
this.b();-----------修改成--------->((AService) AopContext.currentProxy()).b();
3、执行测试用例,日志以下
org.springframework.beans.factory.support.DefaultListableBeanFactory Returning cached instance of singleton bean 'txManager'
org.springframework.orm.hibernate4.HibernateTransactionManager Creating new transaction with name [com.sishuok.service.impl.AServiceImpl2.a]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; '' -----建立a方法事务
org.springframework.orm.hibernate4.HibernateTransactionManager Opened new Session ……for Hibernate transaction --打开a Session
org.springframework.orm.hibernate4.HibernateTransactionManager Preparing JDBC Connection of Hibernate Session ……
org.springframework.orm.hibernate4.HibernateTransactionManager Exposing Hibernate transaction as JDBC transaction ……
……
org.springframework.transaction.support.TransactionSynchronizationManager Initializing transaction synchronization
org.springframework.transaction.interceptor.TransactionInterceptor Getting transaction for [com.sishuok.service.impl.AServiceImpl2.a]
org.springframework.transaction.annotation.AnnotationTransactionAttributeSource Adding transactional method 'b' with attribute: PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT; ''
……
org.springframework.orm.hibernate4.HibernateTransactionManager Suspending current transaction, creating new transaction with name [com.sishuok.service.impl.AServiceImpl2.b] -----建立b方法事务(并暂停a方法事务)
……
org.springframework.orm.hibernate4.HibernateTransactionManager Opened new Session for Hibernate transaction ---打开b Session
……
org.springframework.transaction.support.TransactionSynchronizationManager Initializing transaction synchronization
org.springframework.transaction.interceptor.TransactionInterceptor Getting transaction for [com.sishuok.service.impl.AServiceImpl2.b]
org.springframework.transaction.interceptor.TransactionInterceptor Completing transaction for [com.sishuok.service.impl.AServiceImpl2.b] ----完成b方法事务
org.springframework.orm.hibernate4.HibernateTransactionManager Triggering beforeCommit synchronization
org.springframework.orm.hibernate4.HibernateTransactionManager Triggering beforeCompletion synchronization
org.springframework.orm.hibernate4.HibernateTransactionManager Initiating transaction commit
org.springframework.orm.hibernate4.HibernateTransactionManager Committing Hibernate transaction on Session …… ---提交b方法事务
org.springframework.orm.hibernate4.HibernateTransactionManager Triggering afterCommit synchronization
org.springframework.orm.hibernate4.HibernateTransactionManager Triggering afterCompletion synchronization
org.springframework.transaction.support.TransactionSynchronizationManager Clearing transaction synchronization
……
org.springframework.orm.hibernate4.HibernateTransactionManager Closing Hibernate Session …… after transaction --关闭 b Session
-----到此b方法事务完毕
org.springframework.orm.hibernate4.HibernateTransactionManager Resuming suspended transaction after completion of inner transaction ---恢复a方法事务
……
org.springframework.transaction.support.TransactionSynchronizationManager Initializing transaction synchronization
org.springframework.transaction.interceptor.TransactionInterceptor Completing transaction for [com.sishuok.service.impl.AServiceImpl2.a] ----完成a方法事务
org.springframework.orm.hibernate4.HibernateTransactionManager Triggering beforeCommit synchronization
org.springframework.orm.hibernate4.HibernateTransactionManager Triggering beforeCompletion synchronization
org.springframework.orm.hibernate4.HibernateTransactionManager Initiating transaction commit
org.springframework.orm.hibernate4.HibernateTransactionManager Committing Hibernate transaction on Session ……---提交a方法事务
org.springframework.orm.hibernate4.HibernateTransactionManager Triggering afterCommit synchronization
org.springframework.orm.hibernate4.HibernateTransactionManager Triggering afterCompletion synchronization
org.springframework.transaction.support.TransactionSynchronizationManager Clearing transaction synchronization
……
org.springframework.orm.hibernate4.HibernateTransactionManager Closing Hibernate Session …… after transaction --关闭 a Session
此处咱们能够看到b方法的事务起做用了。
以上方式是解决目标对象内部方法自我调用并实施事务的最简单的解决方案。
4、实现原理分析
4.一、在进入代理对象以后经过AopContext.serCurrentProxy(proxy)暴露当前代理对象到ThreadLocal,并保存上次ThreadLocal绑定的代理对象为oldProxy;
4.二、接下来咱们能够经过 AopContext.currentProxy() 获取当前代理对象;
4.三、在退出代理对象以前要从新将ThreadLocal绑定的代理对象设置为上一次的代理对象,即AopContext.serCurrentProxy(oldProxy)。
有些人不喜欢这种方式,说经过ThreadLocal暴露有性能问题,其实这个不须要考虑,由于事务相关的(Session和Connection)内部也是经过SessionHolder和ConnectionHolder暴露到ThreadLocal实现的。
不过自我调用这种场景确实只有不多状况遇到,所以不用这种方式咱们也能够经过以下方式实现。
此处日志就不分析,和3.1相似。此种方式不是很灵活,全部须要自我调用的实现类必须重复实现代码。
此种解决方案能够参考http://fyting.iteye.com/blog/109236。
BeanPostProcessor 的介绍和使用敬请等待个人下一篇分析帖。
1、定义BeanPostProcessor 须要使用的标识接口
即咱们自定义的BeanPostProcessor (InjectBeanSelfProcessor)若是发现咱们的Bean是实现了该标识接口就调用setSelf注入代理对象。
2、Bean实现
实现BeanSelfAware标识接口的setSelf将代理对象注入,而且经过“proxySelf.b()”这样能够实施b方法的事务定义。
3、InjectBeanSelfProcessor实现
postProcessAfterInitialization根据目标对象是否实现BeanSelfAware标识接口,经过setSelf(bean)将代理对象(bean)注入到目标对象中,从而能够完成目标对象内部的自我调用。
关于BeanPostProcessor的执行流程等请必定参考个人这篇帖子,不然没法继续往下执行。
4、InjectBeanSelfProcessor的问题
(1、场景:经过InjectBeanSelfProcessor进行注入代理对象且循环依赖场景下会产生前者没法经过setSelf设置代理对象的问题。 循环依赖是应该避免的,可是实际工做中不可避免会有人使用这种注入,毕竟没有强制性。
(2、用例
(2.1、定义BeanPostProcessor 须要使用的标识接口
和3.1中同样此处再也不重复。
(2.2、Bean实现
此处A依赖B,B依赖A,即构成循环依赖,此处不探讨循环依赖的设计问题(实际工做应该避免循环依赖),只探讨为何循环依赖会出现注入代理对象失败的问题。
循环依赖请参考个人博文【http://jinnianshilongnian.iteye.com/blog/1415278】。
依赖的初始化和销毁顺序请参考个人博文【http://jinnianshilongnian.iteye.com/blog/1415461】。
(2.3、InjectBeanSelfProcessor实现
和以前3.3中同样 此处再也不重复。
(2.4、测试用例
执行如上测试用例会输出:
BService=true
AService==false
即BService经过InjectBeanSelfProcessor注入代理对象成功,而AService却失败了(实际是注入了目标对象),以下是debug获得的信息:
(2. 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使用的是同样的
转载出处:::http://www.iteye.com/topic/1122740