应用Spring AOP(二)-------通过Advisor指定切入点

       上一篇日志使用的前置通知,后置通知,环绕通知和异常通知可以很好的拦截方法,并插入相应的代码。但是却存在一个问题,就是Spring AOP拦截了目标类中的所有方法。而在通常情况下,只需要拦截部分方法,比如只需要拦截目标类中方法名以set开始的所有方法。Spring AOP提供了Advisor和PointcutAdvisor来达到这个目的。

       常用的PointAdvisor有三种,DefaultPointcutAdvisor , RegexpMethodPointcutAdvisor 和 NameMatchMethodPointcutAdvisor,它们都在org.springframework.aop.support包中。由它们的名字可以看出,RegexpMethodPointcutAdvisor是通过正则表达式来匹配拦截的方法,NameMatchMethodPointcutAdvisor通过直接指定那些方法是需要拦截的,它也可以用*作为通配符。DefaultPointcutAdvisor则需要自定义切入点类。

       在上一篇日志的工程基础上的示例工程代码:
应用Spring AOP(二)-------通过Advisor指定切入点
 结构没多少差别,就是com.aop包中多了一个MyPointcut类。当然applicationContext.xml文件内容也变化了,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans
	xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
	
	<bean id="myUserService" class="com.service.UserService"></bean>
	
	<!-- 定义前置通知 -->
    <bean id="beforeLogAdvice" class="com.aop.BeforeLogAdvice"></bean>
    <bean id="beforePointcut" class="com.aop.MyPointcut"></bean>
    <bean id="myAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
      <property name="pointcut">
          <ref local="beforePointcut"/>
      </property>
      <property name="advice">
          <ref local="beforeLogAdvice"/>
      </property>
    </bean>
    
    <!-- 定义后置通知 -->
	<bean id="afterLogAdvice" class="com.aop.AfterLogAdvice"></bean>
	<bean id="regexpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
      <property name="patterns">
         <list>
           <value>.*deleteUser</value>
         </list>
      </property>
      <property name="advice">
          <ref local="afterLogAdvice"/>
      </property>
    </bean>
	
	<!-- 定义环绕通知 -->
	<bean id="logAroundAdvice" class="com.aop.LogAroundAdvice"></bean>
    <bean id="myAroundAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">  
      <property name="mappedNames">
        <list>
          <value>*User</value>
        </list>
      </property>
      <property name="advice">
        <ref local="logAroundAdvice" />
      </property>
    </bean>
	
	<!-- 定义异常通知 -->
	<bean id="throwsLogAdvice" class="com.aop.ThrowsLogAdvice"></bean>
    
	
    <!-- 定义代理类,名 称为myProxy,将通过myProxy访问业务类中的方法 -->
	<bean id="myProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
	  <property name="proxyInterfaces">
	    <value>com.service.IUserService</value>
	  </property>
	  <property name="interceptorNames">
	    <list>	     
	     <value>myAdvisor</value>
	     
	     <value>regexpAdvisor</value>
	     
	     <value>myAroundAdvisor</value>
	     
	     <value>throwsLogAdvice</value>
	    </list>
	  </property>
	  <property name="target" ref="myUserService"></property>
	</bean>
</beans>

对比上一个工程applicationContext.xml文件的内容,id为myProxy的bean里的interceptorNames拦截器名的list下不再是四个通知了。前置通知,后置通知和环绕通知都变成了Advisor。下面挨个来看。

 

首先看前置通知:

<!-- 定义前置通知 -->
    <bean id="beforeLogAdvice" class="com.aop.BeforeLogAdvice"></bean>
    <bean id="beforePointcut" class="com.aop.MyPointcut"></bean>
    <bean id="myAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
      <property name="pointcut">
          <ref local="beforePointcut"/>
      </property>
      <property name="advice">
          <ref local="beforeLogAdvice"/>
      </property>
    </bean>

 这里自定义了一个MyPointcut切入点类:

package com.aop;

import java.lang.reflect.Method;

import org.springframework.aop.support.NameMatchMethodPointcut;

public class MyPointcut extends NameMatchMethodPointcut {

	public boolean matches(Method method, Class targetClass) {
		this.setMappedName("addUser");
		//this.setMappedName("*User");
		return super.matches(method, targetClass);
	}
}

        Spring AOP在调动目标类的每一个方法之前,都会调用这里的matches方法来判断是否应该拦截该方法,当matches方法返回true时,表明当前方法应该被拦截。如果要想指定被拦截的方法,需要调用NameMatchMethodPointcut的setMappedName方法。本例中指定了addUser方法。当然也可以使用*作为通配符。如代码中的注释,this.setMappedName("*User")将会拦截以User结尾的所有方法。

        要想使用自定义的这个Pointcut类,必须装配DefaultPointcutAdvisor,即applicationContext.xml中id为myAdvisor的bean。这个bean中的pointcut属性指定了切入点,advice属性指定了通知。

 

再来看看后置通知:

<!-- 定义后置通知 -->
	<bean id="afterLogAdvice" class="com.aop.AfterLogAdvice"></bean>
	<bean id="regexpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
      <property name="patterns">
         <list>
           <value>.*deleteUser</value>
         </list>
      </property>
      <property name="advice">
          <ref local="afterLogAdvice"/>
      </property>
    </bean>

 这里用到了RegexpMethodPointcutAdvisor。bean下的patterns属性下添加一些正则表达式规则,能够匹配这些规则的方法就会被拦截。值得一提的是,这儿匹配的是方法的完整路径,包括类名已经类的包名。回顾一下,这儿的目标类是com.service.UserService,它里面只有两个方法addUser和deleteUser。这两个方法的完整路径就是com.service.UserService.addUser 和  com.service.UserService.deleteUser 。这儿写的正则表达式是.*deleteUser ,明显它可以匹配com.service.UserService.deleteUser,所以这个方法会被拦截。假设将正则表达式写成deleteUser,那么它不能匹配com.service.UserService.deleteUser 这整个字符串,所以讲不会起作用。如果要拦截方法名中包含abc的方面,正则表达式写成.*abc.*就可以了(当然包名和类名不能是abc啦)。

 

最后看看环绕通知:

<!-- 定义环绕通知 -->
	<bean id="logAroundAdvice" class="com.aop.LogAroundAdvice"></bean>
    <bean id="myAroundAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">  
      <property name="mappedNames">
        <list>
          <value>*User</value>
        </list>
      </property>
      <property name="advice">
        <ref local="logAroundAdvice" />
      </property>
    </bean>

 这里用到了NameMatchMethodPointcutAdvisor,它的mappedNames属性下添加想要拦截的方法名就可以了,当然也可以用*通配符啦,*User就代表所有以User结尾的方法。注意这儿只匹配方法名,不会管类名和包名了。

 

工程代码在附件中。。。。

你可能感兴趣的:(spring,AOP,Advisor)