前言:
前面介紹了Spring的核心子產品以及相關的依賴注入等概念。這篇講解一下spring的另一個重點,AOP面向切面程式設計。
說道AOP不得不提到幾個概念:
切面:也就是我們自己的一些業務方法。
通知:用于攔截時出發的操作。
切點:具體攔截的某個業務點。
這樣說可能還是有點抽象,舉個例子,下面是一個紙糊的多面體。

每個面都是一個業務方法,我們通過刺穿每一個面,都可以進入到内部,這個面就是一個切面。
刺穿的時候會發出聲響,這就是一種通知。
而具體從哪個面刺入,這就是一個切入點的選擇了。
這樣說,應該能稍微了解一點。
那麼下面看一個簡單的例子:
為了便于理清關系,先放上一張相關的類圖:
首先定義個接口
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權威指南》
作者:xingoo
出處:http://www.cnblogs.com/xing901022
本文版權歸作者和部落格園共有。歡迎轉載,但必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接!