Spring之AOP模塊
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>