前言:html
前面介紹了Spring的核心模塊以及相關的依賴注入等概念。這篇講解一下spring的另外一個重點,AOP面向切面編程。java
說道AOP不得不提到幾個概念:web
切面:也就是咱們本身的一些業務方法。正則表達式
通知:用於攔截時出發的操做。spring
切點:具體攔截的某個業務點。編程
這樣說可能仍是有點抽象,舉個例子,下面是一個紙糊的多面體。app
每一個面都是一個業務方法,咱們經過刺穿每個面,均可以進入到內部,這個面就是一個切面。函數
刺穿的時候會發出聲響,這就是一種通知。測試
而具體從哪一個面刺入,這就是一個切入點的選擇了。this
這樣說,應該能稍微瞭解一點。
爲了便於理清關係,先放上一張相關的類圖:
首先定義個接口
1 public interface IService { 2 public void withAop(); 3 public void withoutAop(); 4 }
有了接口,固然須要一個實現類:
1 public class TestAOP implements IService { 2 private String name; 3 public void withAop() { 4 System.out.println("with AOP name:"+name); 5 } 6 public void withoutAop() { 7 System.out.println("without AOP name:"+name); 8 } 9 public String getName() { 10 return name; 11 } 12 public void setName(String name) { 13 this.name = name; 14 } 15 }
這個實現類實現了接口定義的兩個方法,下面咱們定義幾種攔截方式,這些攔截方式經過攔截的位置或者時機不一樣而不一樣。
一般有方法前攔截,方法後攔截,以及異常攔截。經過在這些攔截中編寫本身的業務處理,能夠達到特定的需求。
方法前攔截,須要實現MethodBeforeAdvice接口,並填寫before方法。這樣,當攔截到某個方法時,就會在方法執行前執行這個before()方法。
1 public class BeforeAOPInterceptor implements MethodBeforeAdvice{ 2 public void before(Method method, Object[] args, Object instance) 3 throws Throwable { 4 System.out.println("before()"+method.getName()); 5 } 6 }
同理,方法後攔截,也是如此。須要實現AfterReturningAdvice接口。
1 public class AfterAOPInterceptor implements AfterReturningAdvice{ 2 public void afterReturning(Object value, Method method, Object[] args, 3 Object instance) throws Throwable { 4 System.out.println("after()"+method.getName()); 5 } 6 }
以及異常攔截。
1 public class ThrowsAOPInterceptor implements ThrowsAdvice{ 2 public void afterThrowing(Method method,Object[] args,Object instance,AccountException ex) throws Throwable{ 3 System.out.println("after()"+method.getName()+"throws exception:"+ex); 4 } 5 public void afterThrowing(NullPointerException ex) throws Throwable{ 6 System.out.println("throws exception:"+ex); 7 } 8 }
接下來就須要配置一下spring的配置文件,把攔截器與切面方法關聯起來。
參考上面的圖,能夠看到配置文件中的層次關係。
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xmlns="http://www.springframework.org/schema/beans" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> 6 <!-- 經過名字匹配 --> 7 <!-- 8 <bean id="before" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"> 9 <property name="advice"> 10 <bean class="com.test.pointcut.beforeAOP"></bean> 11 </property> 12 <property name="mappedName" value="withoutAop"></property> 13 </bean> 14 --> 15 <!-- 經過正則表達式 匹配 --> 16 <bean id="before" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> 17 <property name="advice"> 18 <bean class="com.test.pointcut.BeforeAOPInterceptor"></bean> 19 </property> 20 <property name="patterns"> 21 <list> 22 <value>.*out.*</value> 23 </list> 24 </property> 25 </bean> 26 <bean id="after" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> 27 <property name="advice"> 28 <bean class="com.test.pointcut.AfterAOPInterceptor"></bean> 29 </property> 30 <property name="patterns"> 31 <list> 32 <value>.*out.*</value> 33 </list> 34 </property> 35 </bean> 36 <bean id="exception" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> 37 <property name="advice"> 38 <bean class="com.test.pointcut.ThrowsAOPInterceptor"></bean> 39 </property> 40 <property name="patterns"> 41 <list> 42 <value>.*out.*</value> 43 </list> 44 </property> 45 </bean> 46 <!-- --> 47 <bean id="aopService" class="org.springframework.aop.framework.ProxyFactoryBean"> 48 <property name="interceptorNames"> 49 <list> 50 <value>before</value> 51 <value>after</value> 52 <value>exception</value> 53 </list> 54 </property> 55 <property name="target"> 56 <bean class="com.test.pointcut.TestAOP"> 57 <property name="name" value="Hello"></property> 58 </bean> 59 </property> 60 </bean> 61 </beans>
ProxyFactoryBean下有兩個屬性,一個想要攔截的目標類,一個是攔截器。而攔截器又包括兩種,主要是由於定位方法的不一樣而分類。分別是:
RegexpMethodPointcutAdvisor 經過正則表達式來定位業務方法。
NameMatchMethodPointcutAdvisor 經過名字來定位業務方法。
定位到了業務方法,還須要添加響應的攔截器,攔截器就是上面的三種。
最後看一下測試的方法:
public class TestMain {
public static void main(String[] args) {
XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("applicationContextAOP.xml"));
IService hello = (IService)factory.getBean("aopService");
hello.withAop();
hello.withoutAop();
}
}
咱們上面經過正則表達式定位到全部包含out的方法,其實就是withoutAOP方法。這樣當執行withoutAop方法時,會觸發攔截器的操做。
執行結果:
2014-12-4 16:46:58 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContextAOP.xml]
with AOP name:Hello
before()withoutAop
without AOP name:Hello
after()withoutAop
這是經過定義切入點的方式來實現AOP,經過這種編程方式,能夠針對業務方法進行包裝或者監控。
舉個例子,好比有個業務方法想要進行數據的查詢,那麼能夠再這個查詢前面獲取JDBC鏈接池的鏈接,這樣就對用戶屏蔽掉了複雜的申請過程。而銷燬就能夠放在方法後攔截函數裏。
再好比,想要監控某個業務方法唄執行了多少次,那麼就能夠經過這樣一種攔截方式,進行信息的統計,計數或者計時!
妙處多多,還待完善!
參考:《java web王者歸來》《spring實戰》《spring權威指南》