1. 程式人生 > >spring中BeanNameAutoProxyCreator和AnnotationAwareAspectJAutoProxyCreator兩種AOP代理方式使用總結

spring中BeanNameAutoProxyCreator和AnnotationAwareAspectJAutoProxyCreator兩種AOP代理方式使用總結

昨天程式碼review的過程中,我們遇到了兩種AOP代理的方式,一種是BeanNameAutoProxyCreator,另外一種是AnnotationAwareAspectJAutoProxyCreator。當時大家問這兩種有和區別,十年的老司機

底氣並不足的描述書寫方式不一樣。那麼今天,我們就徹底剖析下兩種代理。

其實,在spring內部,是通過BeanPostProcessor(《spring攻略》一書中翻譯為,後處理器)來完成自動建立代理工作的。根據匹配規則的不同大致分為三種類別:

1、匹配Bean的名稱自動建立匹配到的Bean的代理,實現類BeanNameAutoProxyCreator

2、根據Bean中的AspectJ註解自動建立代理,實現類AnnotationAwareAspectJAutoProxyCreator

3、根據Advisor的匹配機制自動建立代理,會對容器中所有的Advisor進行掃描,自動將這些切面應用到匹配的Bean中,實現類DefaultAdvisorAutoProxyCreator

我們現在主要說下12的使用。

構建測試環境,如圖

第一,先來說下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

method="process"pointcut="execution(* com.jd.plugin.dao.aop.*.*(..))"/>
    </
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">

總結,BeanNameAutoProxyCreatorAnnotationAwareAspectJAutoProxyCreator,在執行結果及過程中是一致的,AnnotationAwareAspectJAutoProxyCreator這種方式可以使用spring AspectJExecution表示式 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目錄下面(如本文的第一張圖)。