spring中BeanNameAutoProxyCreator和AnnotationAwareAspectJAutoProxyCreator兩種AOP代理方式使用總結
昨天程式碼review的過程中,我們遇到了兩種AOP代理的方式,一種是BeanNameAutoProxyCreator,另外一種是AnnotationAwareAspectJAutoProxyCreator。當時大家問這兩種有和區別,十年的老司機
底氣並不足的描述書寫方式不一樣。那麼今天,我們就徹底剖析下兩種代理。
其實,在spring內部,是通過BeanPostProcessor(《spring攻略》一書中翻譯為,後處理器)來完成自動建立代理工作的。根據匹配規則的不同大致分為三種類別:
1、匹配Bean的名稱自動建立匹配到的Bean的代理,實現類BeanNameAutoProxyCreator
2、根據Bean中的AspectJ註解自動建立代理,實現類AnnotationAwareAspectJAutoProxyCreator
3、根據Advisor的匹配機制自動建立代理,會對容器中所有的Advisor進行掃描,自動將這些切面應用到匹配的Bean中,實現類DefaultAdvisorAutoProxyCreator
我們現在主要說下1和2的使用。
構建測試環境,如圖
第一,先來說下AnnotationAwareAspectJAutoProxyCreator這種方式,建立spring-config-test-aop-AnnotationAwareAspectJAutoProxyCreator.xml
<aop:aspectj-autoproxyproxy-target-class="true"/>
<bean id="annotationAwareAspectJAutoProxyCreatorTest"class="com.jd.plugin.dao.aop.AnnotationAwareAspectJAutoProxyCreatorTest"/>
<aop:config>
<aop:aspectref="annotationAwareAspectJAutoProxyCreatorTest">
<aop:around
</aop:aspect>
</aop:config>
建立類檔案,AnnotationAwareAspectJAutoProxyCreatorTest,如下
/** * Created by wangxindong on 2016/11/15. */ public class AnnotationAwareAspectJAutoProxyCreatorTest { private final Logger logger = LoggerFactory.getLogger(this.getClass()); public Object process(ProceedingJoinPoint point) throws Throwable { try { String clazzName = point.getTarget().getClass().getSimpleName(); String methodName = point.getSignature().getName(); logger.debug("hello BeanNameAutoProxyCreator ,i come,clazzName [{}] methodName [{}]",clazzName,methodName); return point.proceed(); } catch (Throwable throwable) { return throwable; } finally { } } }
建立測試類,仍然是使用spring-test方式來測試(好處上次說了,只加載跟本次測試有關係的配置檔案)
/** * Created by wangxindong on 2016/11/7. */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"classpath*:/aop-test/spring-config-test-aop-AnnotationAwareAspectJAutoProxyCreator.xml","classpath*:/aop-test/spring-config-test-service.xml"}) public class DaoUmpInterceptorTest { // @Resource // private PluginOrderManager pluginOrderManager; @Resource private AopUmpMysqlTestMapper aopUmpMysqlTestMapper; @Test public void testUmp(){ // long orderId = 27L; // pluginOrderManager.selectNPOrderInfo(orderId); aopUmpMysqlTestMapper.selectObjectById(); } }
輸出如下:
hello BeanNameAutoProxyCreator ,i come,clazzName [{AopUmpMysqlTestMapperImpl}] methodName [{selectObjectById}]
第二,再來測試下,BeanNameAutoProxyCreator方式,
建立spring-config-test-aop-BeanNameAutoProxyCreator.xml檔案,如下
<bean id="beanNameAutoProxyCreatorTest" class="com.jd.plugin.dao.aop.BeanNameAutoProxyCreatorTest"> </bean> <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="beanNames"> <value>*Mapper</value> </property> <property name="interceptorNames"> <list> <value>beanNameAutoProxyCreatorTest</value> </list> </property> </bean>
測試輸出如下
hello BeanNameAutoProxyCreator ,i come,clazzName [{AopUmpMysqlTestMapper}] methodName [{selectObjectById}]
可以看出這兩種方式,通過debug模式執行,過程和結果都一致。
在來看他們各自的整合類,可以看到他們集成了共同的類。
<xsd:documentationsource="java:org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator">
總結,BeanNameAutoProxyCreator和AnnotationAwareAspectJAutoProxyCreator,在執行結果及過程中是一致的,AnnotationAwareAspectJAutoProxyCreator這種方式可以使用spring AspectJ的Execution表示式 AspectJ表示式除了execution還有其他的如args()、within()、target()等
另外,在Spring AOP中支援4中型別的通知:
1:before advice 在方法執行前執行。
2:after returning advice 在方法執行後返回一個結果後執行。
3:after throwing advice 在方法執行過程中丟擲異常的時候執行。
4:Around advice 在方法執行前後和丟擲異常時執行,相當於綜合了以上三種通知。
到最後,再重申一下,單元測試是必要的,單元測試建議使用spring-test框架,單元測試的檔案統一放到test目錄下面(如本文的第一張圖)。