上边的结果中,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>
运行结果: