Spring 的通知只能织入到目标对象的所有方法,但是没有办法指定织入到哪几个方法,顾问就解决了这个问题。
NameMatchMethodPointcutAdvisor(名称匹配方法切入点顾问)
顾问其实是对通知的封装与延伸,所以配置顾问前仍需要配置通知。
-
编写一个实现了 MethodBeforeAdvice 接口的通知(以前置通知为例)
package com.aop.advice; import java.lang.reflect.Method; import java.util.Arrays; import org.springframework.aop.MethodBeforeAdvice; public class MyBeforeAdvice implements MethodBeforeAdvice { @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("前置通知"); System.out.println(method); System.out.println(Arrays.toString(args)); System.out.println(target); } }
-
在 Spring 的配置文件中注册前置通知
<!-- 注册前置通知 --> <bean id="beforeAdvice" class="com.aop.advice.MyBeforeAdvice"></bean>
-
在 Spring 的配置文件中注册顾问
<!-- 注册一个前置顾问 --> <bean id="beforeAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"> <property name="advice" ref="beforeAdvice" /> <!-- <property name="mappedNames" value="addUser" /> --> <!-- <property name="mappedNames" value="addUser,delUser,updateUser" /> --> <!-- <property name="mappedNames"> <array> <value>addUser</value> <value>delUser</value> <value>updateUser</value> </array> </property> --> <!-- 带User的方法会被织入切面(共四个) --> <property name="mappedNames" value="*User*" /> </bean>
主要注入两个属性:advice, mappedNames。mappedNames 的四种配置方式如上。
-
配置顾问的代理工厂
<!-- 注册前置顾问的代理生成器 --> <bean id="beforeAdvisorProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="userService" /> <property name="interfaces" value="com.aop.service.IUserService" /> <property name="interceptorNames" value="beforeAdvisor" /> </bean>
顾问和通知的代理生成器都是 org.springframework.aop.framework.ProxyFactoryBean ,都需要配置目标对象(target),目标对象的接口(interfaces),需要注入的通知或者顾问。
-
获取代理对象的实例,测试
@Before public void init() { ac = new ClassPathXmlApplicationContext("applicationContext.xml"); } /** * 前置顾问 */ @Test public void testBeforeAdvisor() { IUserService userService = (IUserService) ac.getBean("beforeAdvisorProxy"); userService.addUser(3, "张三"); userService.delUser(4); userService.updateUser(1, "666"); userService.getUserById(3); }
-
执行结果
RegexpMethodPointcutAdvisor(正则表达式匹配方法切入点顾问)
-
编写一个实现了 AfrerReturningAdvice 接口的后置通知
package com.aop.advice; import java.lang.reflect.Method; import java.util.Arrays; import org.springframework.aop.AfterReturningAdvice; public class MyAfterAdvice implements AfterReturningAdvice { @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("后置通知"); System.out.println("returnValue:" + returnValue); System.out.println(method); System.out.println(Arrays.toString(args)); System.out.println(target); } }
-
在 Spring 的配置文件中注册该后置通知
<!-- 注册后置通知 --> <bean id="afterAdvice" class="com.aop.advice.MyAfterAdvice"></bean>
-
注册正则表达式匹配方法切入点顾问
<!-- 注册一个正则表达式方法匹配切入点顾问 --> <bean id="afterAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice" ref="afterAdvice" /> <property name="patterns"> <array> <value>.*add.*</value> </array> </property> </bean>
-
注册一个代理工厂
<!-- 注册正则表达式匹配方法切入点代理工厂 --> <bean id="afterAdvisorProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="userService" /> <property name="interfaces" value="com.aop.service.IUserService" /> <property name="interceptorNames"> <array> <value>afterAdvisor</value> </array> </property> </bean>
-
获取代理对象,测试
/** * 测试正则表达式匹配方法切入点顾问 */ @Test public void testRegAfterAdvice() { IUserService userService = (IUserService) ac.getBean("afterAdvisorProxy"); userService.delUser(4); // userService.addUser(1, "2"); }
-
执行结果:
正则表达式回顾:
- * 匹配前面的子表达式任意次,比如:ao 能匹配 a ao aoo aoooo…*
- + 匹配前面的字表达式一次或者多次,比如:ao+ 能匹配 ao aoo aooo… 但是不能匹配 a
- . 匹配任意一个字符,换行符除外(\r\n)
- . 匹配任意字符串,比如:.add. 能匹配包含 add 的字符串*