Spring AOP四种创建通知(拦截器)类型

taotaoSi 2010-08-16

1、Spring只支持方法拦截,也就是说,只能在方法的前后进行拦截,而不能在属性前后进行拦截。

2、Spring支持四种拦截类型:目标方法调用前(before),目标方法调用后(after),目标方法调用前后(around),以及目标方法抛出异常(throw)。

3、前置拦截的类必须实现MethodBeforeAdvice接口,实现其中的before方法。

4、后置拦截的类必须实现AfterReturningAdvice接口,实现其中的afterReturning方法。

5、前后拦截的类必须实现MethodInterceptor接口,实现其中的invoke方法。前后拦截是唯一可以控制目标方法是否被真正调用的拦截类型,也可以控制返回对象。而前置拦截或后置拦截不能控制,它们不能影响目标方法的调用和返回。

但是以上的拦截的问题在于,不能对于特定方法进行拦截,而只能对某个类的全部方法作拦截。所以下面引入了两个新概念:“切入点”和“引入通知”。

6、”切入点“的定义相当于更加细化地规定了哪些方法被哪些拦截器所拦截,而并非所有的方法都被所有的拦截器所拦截。在ProxyFactoryBean的属性中,interceptorNames属性的对象也由拦截(Advice)变成了引入通知(Advisor),正是在Advisor中详细定义了切入点(PointCut)和拦截(Advice)的对应关系,比如常见的基于名字的切入点匹配(NameMatchMethodPointcutAdvisor类)和基于正则表达式的切入点匹配(RegExpPointcutAdvisor类)。这些切入点都属于”静态切入点“,因为他们只在代理创建的时候被创建一次,而不是每次运行都创建。

下面我们进行实例的开发

首先创建业务接口:

package AdvisorTest;

public interface Shopping ...{

publicStringbuySomething(Stringtype);

publicStringbuyAnything(Stringtype);

publicvoidtestException();

}

下面是业务实现类,我们的通知就是以这些实现类作为切面,在业务方法前后加入我们的通知代码

package AdvisorTest;

public class ShoppingImpl implements Shopping ...{

privateCustomercustomer;

publicCustomergetCustomer()...{

returncustomer;

}

publicvoidsetCustomer(Customercustomer)...{

this.customer=customer;

}

publicStringbuySomething(Stringtype)...{

System.out.println(this.getCustomer().getName()+"bye"+type+"success");

returnnull;

}

publicStringbuyAnything(Stringtype)...{

System.out.println(this.getCustomer().getName()+"bye"+type+"success");

       return null;

     }

publicvoidtestException()...{

thrownewClassCastException();

}

}

(1)前置通知

        配置了前置通知的bean,在执行业务方法前,均会执行前置拦截器的before方法

package AdvisorTest;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

//前置通知

public class WelcomeAdvice implements MethodBeforeAdvice ...{

    public void before(Method method, Object[] args, Object obj)

throwsThrowable...{

Stringtype=(String)args[0];

        System.out.println("Hello welcome to bye "+type);

    }

}

(2)后置通知

配置了后置通知的bean,在执行业务方法后,均会执行后置拦截器的afterReturnning方法 package AdvisorTest;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;

importorg.springframework.aop.MethodBeforeAdvice;

//后置通知

public class ThankYouAdvice implements AfterReturningAdvice ...{

    public void afterReturning(Object obj, Method method, Object[] arg1,

Objectarg2)throwsThrowable...{

Stringtype=(String)arg1[0];

System.out.println("HelloThankyoutobye"+type);

}

   

}

(3)环绕通知

配置了环绕通知的bean,在执行业务方法前后,均会执行环绕拦截器的invoke方法

需要注意的是必须调用目标方法,如不调用,目标方法将不被执行

package AdvisorTest;

import org.aopalliance.intercept.MethodInterceptor;import org.aopalliance.intercept.MethodInvocation;

public class MethodAdvisor implements MethodInterceptor ...{

    public Object invoke(MethodInvocation invocation) throws Throwable ...{

Stringstr=(String)invocation.getArguments()[0];

System.out.println("thisisbefore"+str+"inMethodInterceptor");

Objectobj=invocation.proceed();//调用目标方法,如不调用,目标方法将不被执行

System.out.println("thisisafter"+str+"inMethodInterceptor");

returnnull;

    }

}

(4)异常通知

ThrowsAdvice是一个标示接口,我们可以在类中定义一个或多个,来捕获定义异常通知的bean抛出的异常,并在抛出异常前执行相应的方法

public void afterThrowing(Throwable throwa){}或者

public void afterThrowing(Method method,Object[] args,Object target,Throwable throwable){

package AdvisorTest;

import org.springframework.aop.ThrowsAdvice;

public class ExceptionAdvisor implements ThrowsAdvice ...{

publicvoidafterThrowing(ClassCastExceptione)...{

System.out.println("thisisfromexceptionAdvisor");

}

}

配置文件

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPEbeansPUBLIC"-//SPRING//DTDBEAN//EN""http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

<beanid="customer"class="AdvisorTest.Customer">

<constructor-argindex="0">

<value>gaoxiang</value>

</constructor-arg>

<constructor-argindex="1">

<value>26</value>

</constructor-arg>

</bean>

<beanid="shoppingImpl"class="AdvisorTest.ShoppingImpl">

<propertyname="customer">

<reflocal="customer"/>

</property>

</bean>

<!-- 前置通知 -->

<beanid="welcomeAdvice"class="AdvisorTest.WelcomeAdvice"/>

<beanid="welcomeAdviceShop"class="org.springframework.aop.framework.ProxyFactoryBean">

<propertyname="proxyInterfaces">

<value>AdvisorTest.Shopping</value>

</property>

<propertyname="target">

<reflocal="shoppingImpl"/>

</property>

<propertyname="interceptorNames">

<list>

<value>welcomeAdvice</value>

</list>

</property>

</bean>

<!-- 后置通知 -->

<beanid="thankyouAdvice"class="AdvisorTest.ThankYouAdvice"/>

<beanid="thankyouAdviceShop"class="org.springframework.aop.framework.ProxyFactoryBean">

<propertyname="proxyInterfaces">

<value>AdvisorTest.Shopping</value>

</property>

<propertyname="target">

<reflocal="shoppingImpl"/>

</property>

<propertyname="interceptorNames">

<list>

<value>thankyouAdvice</value>

</list>

</property>

</bean>

<!-- 环绕通知 -->

<beanid="methodAdvice"class="AdvisorTest.MethodAdvisor"/>

<beanid="methodAdviceShop"class="org.springframework.aop.framework.ProxyFactoryBean">

<propertyname="proxyInterfaces">

<value>AdvisorTest.Shopping</value>

</property>

<propertyname="target">

<reflocal="shoppingImpl"/>

</property>

<propertyname="interceptorNames">

<list>

<value>methodAdvice</value>

</list>

</property>

</bean>

<!-- 异常通知 -->

<beanid="exceptionAdvice"class="AdvisorTest.ExceptionAdvisor"/>

<beanid="exceptionAdviceShop"class="org.springframework.aop.framework.ProxyFactoryBean">

<propertyname="proxyInterfaces">

<value>AdvisorTest.Shopping</value>

</property>

<propertyname="target">

<reflocal="shoppingImpl"/>

</property>

<propertyname="interceptorNames">

<list>

<value>exceptionAdvice</value>

</list>

</property>

</bean>

</beans>

测试代码:

package AdvisorTest;

import java.io.File;

import org.springframework.beans.factory.BeanFactory;

importorg.springframework.beans.factory.xml.XmlBeanFactory;

import org.springframework.core.io.FileSystemResource;

public class TestAdvisor ...{

    public static void main(String[] args) ...{

        String filePath=System.getProperty("user.dir")+File.separator+"AdvisorTest"+File.separator+"hello.xml";

BeanFactoryfactory=newXmlBeanFactory(newFileSystemResource(filePath));

Shoppingshopping=null;

System.out.println("不使用任何通知");

shopping=(Shopping)factory.getBean("shoppingImpl");

shopping.buySomething("something");

shopping.buyAnything("anything");

System.out.println("使用前置通知");

shopping=(Shopping)factory.getBean("welcomeAdviceShop");

shopping.buySomething("something");

shopping.buyAnything("anything");

System.out.println("使用后置通知");

shopping=(Shopping)factory.getBean("thankyouAdviceShop");

shopping.buySomething("something");

shopping.buyAnything("anything");

System.out.println("使用环绕通知");

shopping=(Shopping)factory.getBean("methodAdviceShop");

shopping.buySomething("something");

shopping.buyAnything("anything");

System.out.println("使用异常通知");

shopping=(Shopping)factory.getBean("exceptionAdviceShop");

shopping.testException();

   

    }}

运行结果一目了然:

不使用任何通知

gaoxiangbyesomethingsuccess

gaoxiangbyeanythingsuccess

使用前置通知

Hellowelcometobyesomething

gaoxiangbyesomethingsuccess

Hellowelcometobyeanything

gaoxiangbyeanythingsuccess

使用后置通知

gaoxiangbyesomethingsuccess

HelloThankyoutobyesomething

gaoxiangbyeanythingsuccess

HelloThankyoutobyeanything

使用环绕通知

thisisbeforesomethinginMethodInterceptor

gaoxiangbyesomethingsuccess

thisisaftersomethinginMethodInterceptor

thisisbeforeanythinginMethodInterceptor

gaoxiangbyeanythingsuccess

thisisafteranythinginMethodInterceptor

使用异常通知

thisisfromexceptionAdvisor

相关推荐