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>
執行結果: