Spring 面向方面程式設計 AOP
Spring AOP(面向方面程式設計)框架,用於在模組化方面的橫切關注點。簡單得說,它只是一個攔截器,用來攔截一些過程。例如,當一個方法執行,Spring AOP 可以劫持此執行方法,在方法執行之前或之後新增額外的功能。
在Spring AOP中,有 5 種型別通知(advices)的支援:
- 前置通知(Before advice):在目標方法執行之前執行,前置通知不會影響目標方法的執行,除非此處丟擲異常。
- 正常返回通知(After returning advice):在目標方法執行完成後執行,如果目標方法丟擲異常,則不會執行。目標方法執行後,該方法返回一個結果。
- 異常返回通知(After throwing advice):在目標方法丟擲異常後執行。
- 返回通知(After advice):在目標方法執行完成後執行,不管是正常執行完成,還是丟擲異常,都會執行返回通知中的內容。
- 環繞通知(Around advice):環繞通知圍繞在目標方法前後,即一個方法呼叫的前後。這是最強大的通知型別,能在方法呼叫前後自定義一些操作。環繞通知還需要負責決定是繼續處理join point(呼叫ProceedingJoinPoint的proceed方法)還是中斷執行。
1. 前置通知
它會在方法執行之前執行。建立一個實現 MethodBeforeAdvice 介面的類。
public class ArticleServiceMethodBeforeAdvice implements MethodBeforeAdvice {
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("Before " + method.getName() + " of " + target.getClass().getSimpleName() + " class.");
}
}
在 bean 配置檔案(Spring-Bean.xml)配置代理物件。
<bean id="articleDao" class="com.angelia.spring.dao.ArticleDaoImpl">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="articleService" class="com.angelia.spring.service.ArticleServiceImpl" scope="prototype">
<property name="articleDao">
<ref bean="articleDao" />
</property>
</bean>
<bean id="articleServiceBeforeAdvice" class="com.angelia.spring.dao.aop.ArticleServiceMethodBeforeAdvice" />
<bean id="articleServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="articleService" />
<property name="interceptorNames">
<list>
<value>articleServiceBeforeAdvice</value>
</list>
</property>
</bean>
‘target’ – 定義你想攔截的bean。‘interceptorNames’ – 定義要應用這個代理/目標物件的類(通知)。
2. 正常返回通知
該方法返回一個結果之後它將執行。建立一個實現AfterReturningAdvice介面的類。
public class ArticleServiceAfterReturningAdvice implements AfterReturningAdvice {
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("After return result of the " + method.getName() + " of " + target.getClass().getSimpleName() + " class.");
}
}
bean配置檔案
<bean id="articleServiceAfterAdvice" class="com.angelia.spring.dao.aop.ArticleServiceAfterReturningAdvice" />
<bean id="articleServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="articleService" />
<property name="interceptorNames">
<list>
<value>articleServiceBeforeAdvice</value>
<value>articleServiceAfterAdvice</value>
</list>
</property>
</bean>
3. 異常返回通知
它將在執行方法丟擲一個異常後。建立一個實現ThrowsAdvice介面的類,並建立一個afterThrowing方法攔截丟擲:IllegalArgumentException異常
public class ArticleServiceThrowsAdvice implements ThrowsAdvice {
public void afterThrowing(IllegalArgumentException e) throws Throwable {
System.out.println("ArticleServiceThrowsAdvice : Throw exception in ArticleServiceImpl!");
}
}
bean配置檔案
<bean id="articleServiceThrowsAdvice" class="com.angelia.spring.dao.aop.ArticleServiceThrowsAdvice" />
<bean id="articleServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="articleService" />
<property name="interceptorNames">
<list>
<value>articleServiceBeforeAdvice</value>
<value>articleServiceAfterAdvice</value>
<value>articleServiceThrowsAdvice</value>
</list>
</property>
</bean>
4. 返回通知
該方法執行完成後執行,不管是正常執行完成,還是丟擲異常,都會執行返回通知中的內容。建立一個實現AfterAdvice介面的類。
public class ArticleServiceAfterAdvice implements AfterAdvice {
public void after(Method method, Object[] args, Object target) throws Throwable {
System.out.println("After " + method.getName() + " of " + target.getClass().getSimpleName() + " class.");
}
}
bean配置
<bean id="articleServiceAfterAdvice" class="com.angelia.spring.dao.aop.ArticleServiceAfterAdvice" />
<bean id="articleServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="articleService" />
<property name="interceptorNames">
<list>
<value>articleServiceAfterAdvice</value>
</list>
</property>
</bean>
5. 環繞通知
環繞通知結合了上面的三個通知,在方法執行過程中執行。建立一個實現了MethodInterceptor介面的類。
public class ArticleServiceAroundMethod implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
// MethodBeforeAdvice
System.out.println("ArticleServiceMethodBeforeAdvice...");
try {
// 執行原來的方法
Object result = invocation.proceed();
// AfterReturningAdvice
System.out.println("ArticleServiceAfterReturningAdvice...");
return result;
} catch (IllegalArgumentException e) {
// ThrowsAdvice
System.out.println("ArticleServiceThrowsAdvice...");
throw e;
}
}
}
必須呼叫“invocation.proceed();” 繼續在原來的方法執行,否則原來的方法將不會執行。
bean配置檔案
<bean id="articleServiceAroundMethod" class="com.angelia.spring.dao.aop.ArticleServiceAroundMethod" />
<bean id="articleServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="articleService" />
<property name="interceptorNames">
<list>
<!-- <value>articleServiceBeforeAdvice</value>
<value>articleServiceAfterAdvice</value>
<value>articleServiceThrowsAdvice</value> -->
<value>articleServiceAroundMethod</value>
</list>
</property>
</bean>
在每一個 ArticleService 方法執行後,將執行 ArticleServiceAroundMethod 的 invoke() 方法。
6. Spring AOP 切入點 (Pointcut,Advisor)
上面的Spring AOP通知的例子,一個類的整個方法被自動攔截。但在大多數情況下,可能只需要一種方式來攔截部分方法,這就是為什麼引入'切入點'的原因。它允許你根據method的名字去攔截指定的method。另外,一個Pointcut必須結合一個Advisor來使用。
在Spring AOP中,有3個常用的概念,Advices、Pointcut、Advisor。
- Advices:表示一個method執行前或執行後的動作。
- Pointcut:表示根據method的名字或者正規表示式去攔截一個method。
- Advisor:Advice和Pointcut組成的獨立的單元,並且能夠傳給proxy factory 物件。
前面的例子,ArticleServiceImpl中全部的method方法全部被攔截了,下邊將利用Pointcuts只攔截queryArticleById()。我們可以用名字匹配法和正規表示式匹配法去匹配要攔截的method。
切入點 - 名稱匹配
建立一個NameMatchMethodPointcut的bean,將你想攔截的方法的名字queryArticleById注入到屬性mappedName。建立一個DefaultPointcutAdvisor的advisor bean,將pointcut和advice關聯起來。
<bean id="articleServiceBeforeAdvice" class="com.angelia.spring.dao.aop.ArticleServiceMethodBeforeAdvice" />
<bean id="articlePointcut" class="org.springframework.aop.support.NameMatchMethodPointcut">
<property name="mappedName" value="queryArticleById" />
</bean>
<bean id="articleAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut" ref="articlePointcut" />
<property name="advice" ref="articleServiceBeforeAdvice" />
</bean>
<bean id="articleServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="articleService" />
<property name="interceptorNames">
<list>
<!-- <value>articleServiceBeforeAdvice</value> -->
<value>articleAdvisor</value>
</list>
</property>
</bean>
以上配置中pointcut和advisor可以合併在一起配置,即不用單獨配置articlePointcut和articleAdvisor,只要配置articleAdvisor時class選擇NameMatchMethodPointcutAdvisor如下:
<bean id="articleAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="mappedName" value="queryArticleById" />
<property name="advice" ref="articleServiceBeforeAdvice" />
</bean>
實際上這種做法將 method 名字與具體的advice捆綁在一起,有悖於 Spring 鬆耦合理念,如果將 method 名字單獨配置成pointcut(切入點),advice和pointcut的結合會更靈活,使一個pointcut可以和多個advice結合。
切入點 - 正規表示式
可以用正規表示式匹配需要攔截的method。
<bean id="articleAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="patterns">
<list>
<value>.*Article.*</value>
</list>
</property>
<property name="advice" ref="articleServiceBeforeAdvice" />
</bean>
現在,你可以攔截名字中包含Article字元的method了。
7. Spring自動建立代理
前面的 Spring AOP例子 – advice, pointcut 和 advisor, 必須手動建立一個代理bean(ProxyFactryBean),對每個Bean需要AOP支援。這顯然不是一種有效的方式。例如,如果想在客戶模組,所有的Servic類實現SQL日誌支援的AOP功能,那麼必須手動建立很多代理工廠bean,因此在 bean配置檔案可能會氾濫代理類。幸運的是,Spring有兩個自動代理建立者來自動建立代理bean。
BeanNameAutoProxyCreator
自動代理機制,只需要建立一個的 BeanNameAutoProxyCreator,幷包含所有你的bean(通過bean的名字,或正規表示式名)和“advisor” 作為一個單位。
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>*Service</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>articleAdvisor</value>
</list>
</property>
</bean>
現在,可以通過“articleService”的原始名稱獲取bean, 如果知道這個bean已經代理。
DefaultAdvisorAutoProxyCreator
DefaultAdvisorAutoProxyCreator 是非常強大的,如果有 bean 相關連,Spring會自動建立一個代理。
<bean id="articleServiceBeforeAdvice" class="com.angelia.spring.dao.aop.ArticleServiceMethodBeforeAdvice" />
<bean id="articleAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="mappedName" value="queryArticleById" />
<property name="advice" ref="articleServiceBeforeAdvice" />
</bean>
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />
相關文章
- Spring Boot中面向方面程式設計 (AOP)教程Spring Boot程式設計
- Spring之AOP面向切面程式設計Spring程式設計
- Spring AOP——Spring 中面向切面程式設計Spring程式設計
- Spring AOP(面向切面程式設計)是什麼?Spring程式設計
- AOP 面向切面程式設計程式設計
- AOP(面向切面程式設計)程式設計
- 面向切面程式設計AOP程式設計
- 面向方面的程式設計程式設計
- AOP 面向方面程式設計的介紹----基本概念(2) (轉)程式設計
- AOP 面向方面程式設計的介紹----基本概念(3) (轉)程式設計
- 手寫Spring---AOP面向切面程式設計(4)Spring程式設計
- 手寫Spring---AOP面向切面程式設計(3)Spring程式設計
- Spring 面向切面程式設計AOP 詳細講解Spring程式設計
- Java 面向切面程式設計AOPJava程式設計
- AOP--面向切面程式設計程式設計
- PHP 的面向方面程式設計PHP程式設計
- Spring Boot實戰系列(3)AOP面向切面程式設計Spring Boot程式設計
- Spring之旅第七站:面向切面程式設計(AOP)Spring程式設計
- Day67 Spring AOP(面向切面程式設計) 和代理設計模式Spring程式設計設計模式
- 設計模式之面向切面程式設計AOP設計模式程式設計
- Android AOP面向切面設計程式設計Android程式設計
- 前端js面向切面程式設計(AOP)前端JS程式設計
- Android面向切面程式設計(AOP)Android程式設計
- aop面向切面程式設計的實現程式設計
- Java中的面向切面程式設計(AOP)Java程式設計
- 前端解讀面向切面程式設計(AOP)前端程式設計
- Spring框架系列(4) - 深入淺出Spring核心之面向切面程式設計(AOP)Spring框架程式設計
- 01.AOP(AspectOrientatedProgramming面向切面程式設計)程式設計
- 面向方面程式設計的Annotation簡介(轉)程式設計
- Spring AOP:面向切面程式設計的核心概念與實際應用Spring程式設計
- Spring框架 -- AOP程式設計Spring框架程式設計
- Spring 面向切面AOPSpring
- 【spring原始碼學習】spring的AOP面向切面程式設計的實現解析Spring原始碼程式設計
- Spring-AOP(面向切面)Spring
- spring AOP 程式設計式應用Spring程式設計
- 四、Spring-面向切面程式設計Spring程式設計
- 從原始碼入手,一文帶你讀懂Spring AOP面向切面程式設計原始碼Spring程式設計
- C++設計模式::裝飾模式or代理模式or面向切片程式設計(AOP)C++設計模式程式設計