Spring之AOP模块
n672
10年前
AOP(AspectOriented Programming,面向切面编程)是Spring框架的一个重要特征
Spring推荐使用接口编程
Spring提供三种拦截器:方法前拦截器、返回后拦截器、异常抛出拦截器
拦截器定义
//Service接口 public interface IAopService{ public void withAop() throws Exception; //将会被拦截 public void withoutAop() throws Exception; //不会被拦截 } public class AopServiceImpl implements IAopService{ private String name; public void withAop() throws Exception{ System.out.println("有AOP的函数运行。name:"+name); if(name.trim().length() == 0){ throw new AccountException("name属性不能为空"); } } public void withoutAop() throws Exception{ System.out.println("没有AOP的函数运行。"); } public void setName(String name){ this.name = name; } public String getName(){ return this.name; } }
//方法前拦截器,检查name是否为空 import org.springframework.aop.MethodBeforeAdvice public class MethodBeforeInterceptor implements MethodBeforeAdvice{ //调用对象的方法前执行该方法 //参数分别为被调用的方法、被调用方法的参数、对象 publicvoid before(Method method,Object [] args,Object instance) throws Throwable{ System.out.println("即将执行方法:"+method.getName()); // if(instance instanceof AopServiceImpl){ String name = ((AopServiceImpl)instance).getName(); if(name == null){ throw new NullPointerException("name不能为空"); } } } } //返回后拦截器 import org.springframework.aop.AfterReturningAdvice public class MethodAfterInteceptor implements AfterReturningAdvice{ //参数分别为方法返回值、被调用方法、方法参数、被拦截的对象 publicvoid afterReturning(Object value,Method method,Object [] args,Object instance) throwsThrowable{ System.out.println("方法:"+method.getName()+"执行完毕,返回值为:"+value); } } //异常拦截器捕获异常 import org.springframework.aop.ThrowAdvice public class ThrowsInterceptor implements ThrowAdvice{ //参数分别为被调用的方法、方法参数、对象实例、抛出的异常 //前三个参数可以省略,第四个参数是必须的,这样设计是为了使开发者灵活地定义多个方法捕获各种不同的异常 publicvoid afterThrowing(Method method,Object [] args,Object instance,AccountExceptionex) throws Throwable { System.out.println("方法:"+method.getName()+"抛出了异常:"+ex); } publicvoid afterThrowing(NullPointerException ex) throws Throwable { System.out.println("抛出了异常:"+ex); } }
拦截器配置
Spring无法将Service的实现类与拦截器直接组装,因为没有对应的setter、getter方法。安装时借助的是Spring的代理类,把拦截器安装到NameMatchMethodPointcutAdvisor中,把自动以的Service安装到ProxyFactoryBean中,然后组装到一块
<!--方法前拦截器MethodBeforeInterceptor安装到NameMatchMethodPointcutAdvisor中 --> <bean id="aopMethodBeforeInterceptor" class="org.springframework.aop.support. NameMatchMethodPointcutAdvisor"> <!-- 拦截器的实现类--> <property name="advice"> <bean class="com.clf.spring.MethodBeforeInterceptor"> </property> <!-- 欲拦截的方法名--> <property name="mappedName" value="withAop"> </property> </bean> <!-- 类似的方式配置返回后前拦截器MethodAfterInteceptor --> <bean id="aopMethodAfterInterceptor" class="org.springframework.aop.support. NameMatchMethodPointcutAdvisor"> <property name="advice"> <bean class="com.clf.spring.MethodAfterInteceptor"> </property> <property name="mappedName" value="withAop"> </property> </bean> <!-- 类似的方式配置异常前拦截器MethodAfterInteceptor--> <bean id="aopThrowsInterceptor" class="org.springframework.aop.support. NameMatchMethodPointcutAdvisor"> <property name="advice"> <bean class="com.clf.spring.ThrowsInterceptor"> </property> <property name="mappedName" value="withoutAop"> </property> </bean> <!-- Service实现类,安装到ProxyFactoryBean--> <bean id="aopService" class="org.springframework.aop.ProxyFactoryBean"> <!-- 安装拦截器--> <property name="interceptorNames"> <list> <value>aopMethodBeforeInterceptor</value> <value>aopMethodAfterInterceptor</value> <value>aopThrowsInterceptor</value> </list> </property> <!—被拦截的对象--> <property name="target"> <bean class="com.clf.spring.AopServiceImpl"> <property name="name" value="HelloSpring"></property> </bean> </property> </bean>
AOP相关概念
切面Aspect
在本例中,方法withAop()、withoutAop()中都有一些代码,这些代码可以看做是AOP中的切面,可以将切面理解为模块
通知Advisor
本例的三个拦截器都是实现自某个接口,从类名上看就知道三个拦截器都是AOP中的通知。一旦Spring符合条件,就会派发出通知,即一些需要执行的代码,能实现某种功能
切入点Pointcut
在配置拦截器时,XML中只配置了withAop()方法使用拦截器,而withoutAop()方法没有配置拦截器,这种配置是借助于org.springframework.aop.support. NameMatchMethodPointcutAdvisor完成的。这就是一个切入点,配置时可以使用通配符。该类明上也带有Advisor是因为它也是用通知实现的
简单地说,切入点负责往什么地方插入代码,而通知负责插入什么代码
Spring提供灵活的切入点配置,例如使用正则表达式
<bean id="advisorTest" class="org.springframework.aop.support.RegexMethodPointcutAdvisor"> <property name="interceptor"> <ref local="someInterceptor"> </property> <property name="pattern"> <list> <value>.*get*</value> <value>.*set*</value> </list> </property> </bean>