開濤的解決方案1 http://jinnianshilongnian.iteye.com/blog/1487235
AopContext.currentProxy() 原理
http://books.google.com.hk/books?id=jRVp2INtY1AC&pg=PA104&lpg=PA104&dq=Spring+AopContext&source=bl&ots=KXzss6euqJ&sig=B1LdkDTEACMgdmSSQp9SkMBPiwQ&hl=zh-CN&sa=X&ei=kx1vUoXIE4emkQWS_4CoBQ&ved=0CCkQ6AEwADgU#v=onepage&q&f=false
解決方案2
通過BeanPostProcessor 在目標對象中注入代理對象
public class SomeServiceImpl implements SomeService { public void someMethod() { someInnerMethod(); //foo... } public void someInnerMethod() { //bar... } }
兩個方法經過AOP代理,執行時都實現系統日志記錄。單獨使用someInnerMethod時,沒有任何問題。但someMethod就有問題了。someMethod里調用的someInnerMethod方法是原始的,未經過AOP增強的。我們期望調用一次someMethod會記錄下兩條系統日志,分別是someInnerMethod和someMethod的,但實際上只能記錄下someMethod的日志,也就是只有一條。在配置事務時也可能會出現問題,比如someMethod方法是REQUIRED,someInnerMethod方法是REQUIRES_NEW,someInnerMethod的配置將不起作用,與someMethod方法會使用同一個事務,不會按照所配置的打開新事務。
由於java這個靜態類型語言限制,最后想到個曲線救國的辦法,出現這種特殊情況時,不要直接調用自身方法,而通過AOP代理后的對象。在實現里保留一個AOP代理對象的引用,調用時通過這個代理即可。比如:
//從beanFactory取得AOP代理后的對象 SomeService someServiceProxy = (SomeService)beanFactory.getBean("someService"); //把AOP代理后的對象設置進去 someServiceProxy.setSelf(someServiceProxy); //在someMethod里面調用self的someInnerMethod,這樣就正確了 someServiceProxy.someMethod();
但這個代理對象還要我們手動set進來,幸好SpringBeanFactory有BeanPostProcessor擴展,在bean初始化前后會統一傳遞給BeanPostProcess處理,繁瑣的事情就可以交給程序了,代碼如下,首先定義一個BeanSelfAware接口,實現了此接口的程序表明需要注入代理后的對象到自身。
public class SomeServiceImpl implements SomeService,BeanSelfAware { private SomeService self;//AOP增強后的代理對象 //實現BeanSelfAware接口 public void setSelf(Object proxyBean) { this.self = (SomeService)proxyBean } public void someMethod() { someInnerMethod();//注意這句,通過self這個對象,而不是直接調用的 //foo... } public void someInnerMethod() { //bar... } }
再定義一個BeanPostProcessor,beanFactory中的每個Bean初始化完畢后,調用所有BeanSelfAware的setSelf方法,把自身的代理對象注入自身……
public class InjectBeanSelfProcessor implements BeanPostProcessor { public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if(bean instanceof BeanSelfAware) { System.out.println("inject proxy:" + bean.getClass()); BeanSelfAware myBean = (BeanSelfAware)bean; myBean.setSelf(bean); return myBean; } return bean; } public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } }
最后,在BeanFactory配置中組合起來,只需要把BeanPostProcesser加進去就可以了,比平常多一行配置而已。
<!-- 注入代理后的bean到bean自身的BeanPostProcessor... --> <bean class=" org.mypackage.InjectBeanSelfProcessor"></bean> <bean id="someServiceTarget" class="org.mypackage.SomeServiceImpl" /> <bean id="someService" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target"> <ref local="someServiceTarget" /> </property> <property name="interceptorNames"> <list> <value>someAdvisor</value> </list> </property> </bean> <!-- 調用spring的DebugInterceptor記錄日志,以確定方法是否被AOP增強 --> <bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor" /> <bean id="someAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice"> <ref local="debugInterceptor" /> </property> <property name="patterns"> <list> <value>.*someMethod</value> <value>.*someInnerMethod</value> </list> </property> </bean>