1. 程式人生 > 實用技巧 >Spring 框架的 AOP - 改進

Spring 框架的 AOP - 改進

上邊的結果中,CustomerService.java 中,全部的 method 方法全部被攔截了,下邊我們將展示怎樣利用 Pointcuts 只攔截 printName()。

在 Spring AOP 中,有 3 個常用的概念,Advices、Pointcut、Advisor,解釋如下:

  • Advices:表示一個 method 執行前或執行後的動作。
  • Pointcut:表示根據 method 的名字或者正則表示式去攔截一個 method。
  • Advisor:Advice 和 Pointcut 組成的獨立的單元,並且能夠傳給 proxy factory 物件。

我們可以用名字匹配法和正則表示式匹配法去匹配要攔截的 method。

Pointcut - Name match example

通過 pointcut 和 advisor 攔截 printName() 方法。建立一個 NameMatchMethodPointcut 的 bean,將你想攔截的方法的名字 printName 注入到屬性 mappedName,如下:

<bean id = "customerPointcut"
        class = "org.springframework.aop.support.NameMatchMethodPointcut">
        <property name = "mappedName" value = "printName" />
</bean>

建立一個 DefaultPointcutAdvisor 的 advisor bean,將 pointcut 和 advice 關聯起來。

<bean id = "customerAdvisor"
        class = "org.springframework.aop.support.DefaultPointcutAdvisor">
        <property name = "pointcut" ref = "customerPointcut" />
        <property name = "advice" ref = "hijackAroundMethodBean" />
</bean>

更改代理的 interceptorNames 值,將上邊的 advisor(customerAdvisor)替代原來的 hijackAroundMethodBean。

<bean id = "customerServiceProxy"
        class = "org.springframework.aop.framework.ProxyFactoryBean">

        <property name = "target" ref = "customerService" />

        <property name = "interceptorNames">
            <list>
                <value>customerAdvisor</value>
            </list>
        </property>
</bean>

所有的配置檔案如下:

<beans xmlns = "http://www.springframework.org/schema/beans"
    xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation = "http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id = "customerService" class = "com.shiyanlou.spring.aop.advice.CustomerService">
        <property name = "name" value = "lanqiao" />
        <property name = "url" value = "lanqiao.cn" />
    </bean>

    <bean id = "hijackAroundMethodBean" class = "com.shiyanlou.spring.aop.advice.HijackAroundMethod" />

    <bean id = "customerServiceProxy" class = "org.springframework.aop.framework.ProxyFactoryBean">
        <property name = "target" ref = "customerService" />
        <property name = "interceptorNames">
            <list>
                <value>customerAdvisor</value>
            </list>
        </property>
    </bean>

    <bean id = "customerPointcut" class = "org.springframework.aop.support.NameMatchMethodPointcut">
        <property name = "mappedName" value = "printName" />
    </bean>

    <bean id = "customerAdvisor" class = "org.springframework.aop.support.DefaultPointcutAdvisor">
        <property name = "pointcut" ref = "customerPointcut" />
        <property name = "advice" ref = "hijackAroundMethodBean" />
    </bean>

</beans>

再執行一下 App.java,輸出結果如下:

以上執行結果顯示,只攔截了 printName() 方法。

注意:以上配置中 pointcut 和 advisor 可以合併在一起配置,即不用單獨配置 customerPointcut 和 customerAdvisor,只要配置 customerAdvisor 時 class 選擇 NameMatchMethodPointcutAdvisor 如下:

<bean id = "customerAdvisor" class = "org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
        <property name = "mappedName" value = "printName" />
        <property name = "advice" ref = "hijackAroundMethodBean" />
</bean>

這樣,整個配置檔案如下:

<?xml version = "1.0" encoding = "UTF-8"?>
<beans xmlns = "http://www.springframework.org/schema/beans"
    xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation = "http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

     <bean id = "customerService" class = "com.shiyanlou.spring.aop.advice.CustomerService">
        <property name = "name" value = "lanqiao" />
        <property name = "url" value = "lanqiao.cn" />
    </bean>

    <bean id = "hijackAroundMethodBean" class = "com.shiyanlou.spring.aop.advice.HijackAroundMethod" />

    <bean id = "customerServiceProxy" class = "org.springframework.aop.framework.ProxyFactoryBean">
        <property name = "target" ref = "customerService" />
        <property name = "interceptorNames">
            <list>
                <value>customerAdvisor</value>
            </list>
        </property>
    </bean>


    <bean id = "customerAdvisor" class = "org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
        <property name = "mappedName" value = "printName" />
        <property name = "advice" ref = "hijackAroundMethodBean" />
    </bean>

</beans>

實際上這種做法將 method 名字與具體的 advice 捆綁在一起,有悖於 Spring 鬆耦合理念,如果將 method 名字單獨配置成 pointcut(切入點),advice 和 pointcut 的結合會更靈活,使一個 pointcut 可以和多個 advice 結合。

Pointcut - Regular exxpression match example

你可以配置用正則表示式匹配需要攔截的 method,如下配置:

<bean id = "customerAdvisor" class = "org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name = "patterns">
            <list>
                <value>.*URL.*</value>
            </list>
        </property>
        <property name = "advice" ref = "hijackAroundMethodBean" />
    </bean>

配置檔案詳情如下:

<?xml version = "1.0" encoding = "UTF-8"?>
<beans xmlns = "http://www.springframework.org/schema/beans"
    xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation = "http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id = "customerService" class = "com.shiyanlou.spring.aop.advice.CustomerService">
        <property name = "name" value = "lanqiao" />
        <property name = "url" value = "lanqiao.cn" />
    </bean>

    <bean id = "hijackAroundMethodBean" class = "com.shiyanlou.spring.aop.advice.HijackAroundMethod" />

    <bean id = "customerServiceProxy" class = "org.springframework.aop.framework.ProxyFactoryBean">
        <property name = "target" ref = "customerService" />
        <property name = "interceptorNames">
            <list>
                <value>customerAdvisor</value>
            </list>
        </property>
    </bean>

    <bean id = "customerAdvisor" class = "org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name = "patterns">
            <list>
                <value>.*URL.*</value>
            </list>
        </property>
        <property name = "advice" ref = "hijackAroundMethodBean" />
    </bean>

</beans>

執行結果: