需求:以前的動態選擇數據庫,和如今的將某個service層的方法接入cat,都須要用到切面編程。html
參考文獻:java
http://www.blogjava.net/supercrsky/articles/174368.htmlspring
http://my.oschina.net/itblog/blog/211693數據庫
1、簡介編程
面向切面編程(AOP)提供另一種角度來思考程序結構,經過這種方式彌補了面向對象編程(OOP)的不足。 除了類(classes)之外,AOP提供了 切面。切面對關注點進行模塊化,例如橫切多個類型和對象的事務管理。 (這些關注點術語一般稱做 橫切(crosscutting) 關注點。)緩存
Spring的一個關鍵的組件就是 AOP框架。 儘管如此,Spring IoC容器並不依賴於AOP,這意味着你能夠自由選擇是否使用AOP,AOP提供強大的中間件解決方案,這使得Spring IoC容器更加完善。框架
切面(Aspect): 一個關注點的模塊化,這個關注點可能會橫切多個對象。事務管理是J2EE應用中一個關於橫切關注點的很好的例子。 在Spring AOP中,切面可使用通用類(基於模式的風格) 或者在普通類中以 @Aspect 註解(@AspectJ風格)來實現。ide
鏈接點(Joinpoint): 在程序執行過程當中某個特定的點,好比某方法調用的時候或者處理異常的時候。 在Spring AOP中,一個鏈接點 老是 表明一個方法的執行。 經過聲明一個 org.aspectj.lang.JoinPoint 類型的參數可使通知(Advice)的主體部分得到鏈接點信息。模塊化
通知(Advice): 在切面的某個特定的鏈接點(Joinpoint)上執行的動做。通知有各類類型,其中包括「around」、「before」和「after」等通知。 通知的類型將在後面部分進行討論。許多AOP框架,包括Spring,都是以攔截器作通知模型,並維護一個以鏈接點爲中心的攔截器鏈。spa
切入點(Pointcut): 匹配鏈接點(Joinpoint)的斷言。通知和一個切入點表達式關聯,並在知足這個切入點的鏈接點上運行(例如,當執行某個特定名稱的方法時)。 切入點表達式如何和鏈接點匹配是AOP的核心:Spring缺省使用AspectJ切入點語法。
引入(Introduction): (也被稱爲內部類型聲明(inter-type declaration))。聲明額外的方法或者某個類型的字段。 Spring容許引入新的接口(以及一個對應的實現)到任何被代理的對象。 例如,你可使用一個引入來使bean實現 IsModified 接口,以便簡化緩存機制。
目標對象(Target Object): 被一個或者多個切面(aspect)所通知(advise)的對象。也有人把它叫作 被通知(advised) 對象。 既然Spring AOP是經過運行時代理實現的,這個對象永遠是一個 被代理(proxied) 對象。
AOP代理(AOP Proxy): AOP框架建立的對象,用來實現切面契約(aspect contract)(包括通知方法執行等功能)。 在Spring中,AOP代理能夠是JDK動態代理或者CGLIB代理。 注意:Spring 2.0最新引入的基於模式(schema-based)風格和@AspectJ註解風格的切面聲明,對於使用這些風格的用戶來講,代理的建立是透明的。
織入(Weaving): 把切面(aspect)鏈接到其它的應用程序類型或者對象上,並建立一個被通知(advised)的對象。 這些能夠在編譯時(例如使用AspectJ編譯器),類加載時和運行時完成。 Spring和其餘純Java AOP框架同樣,在運行時完成織入。
通知的類型:
前置通知(Before advice): 在某鏈接點(join point)以前執行的通知,但這個通知不能阻止鏈接點前的執行(除非它拋出一個異常)。
返回後通知(After returning advice): 在某鏈接點(join point)正常完成後執行的通知:例如,一個方法沒有拋出任何異常,正常返回。
拋出異常後通知(After throwing advice): 在方法拋出異常退出時執行的通知。
後通知(After (finally) advice): 當某鏈接點退出的時候執行的通知(不管是正常返回仍是異常退出)。
環繞通知(Around Advice): 包圍一個鏈接點(join point)的通知,如方法調用。這是最強大的一種通知類型。 環繞通知能夠在方法調用先後完成自定義的行爲。它也會選擇是否繼續執行鏈接點或直接返回它們本身的返回值或拋出異常來結束執行。
環繞通知是最經常使用的一種通知類型。大部分基於攔截的AOP框架,例如Nanning和JBoss4,都只提供環繞通知。
切入點(pointcut)和鏈接點(join point)匹配的概念是AOP的關鍵,這使得AOP不一樣於其它僅僅提供攔截功能的舊技術。 切入點使得定位通知(advice)可獨立於OO層次。 例如,一個提供聲明式事務管理的around通知能夠被應用到一組橫跨多個對象中的方法上(例如服務層的全部業務操做)。
2、編程(有兩種,基於註解方式和XML配置方式,介紹基於註解方式的AOP編程)
一、配置文件中須要配置AOP
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd ">
二、
package com.abc.advice;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class AdviceTest {
@Around("execution(* com.abc.service.*.many*(..))")
public Object process(ProceedingJoinPoint point) throws Throwable {
System.out.println("@Around:執行目標方法以前...");
//訪問目標方法的參數:
Object[] args = point.getArgs();
if (args != null && args.length > 0 && args[0].getClass() == String.class) {
args[0] = "改變後的參數1";
}
//用改變後的參數執行目標方法
Object returnValue = point.proceed(args);
System.out.println("@Around:執行目標方法以後...");
System.out.println("@Around:被織入的目標對象爲:" + point.getTarget());
return "原返回值:" + returnValue + ",這是返回結果的後綴";
}
@Before("execution(* com.abc.service.*.many*(..))")
public void permissionCheck(JoinPoint point) {
System.out.println("@Before:模擬權限檢查...");
System.out.println("@Before:目標方法爲:" +
point.getSignature().getDeclaringTypeName() +
"." + point.getSignature().getName());
System.out.println("@Before:參數爲:" + Arrays.toString(point.getArgs()));
System.out.println("@Before:被織入的目標對象爲:" + point.getTarget());
}
@AfterReturning(pointcut="execution(* com.abc.service.*.many*(..))",
returning="returnValue")
public void log(JoinPoint point, Object returnValue) {
System.out.println("@AfterReturning:模擬日誌記錄功能...");
System.out.println("@AfterReturning:目標方法爲:" +
point.getSignature().getDeclaringTypeName() +
"." + point.getSignature().getName());
System.out.println("@AfterReturning:參數爲:" +
Arrays.toString(point.getArgs()));
System.out.println("@AfterReturning:返回值爲:" + returnValue);
System.out.println("@AfterReturning:被織入的目標對象爲:" + point.getTarget());
}
@After("execution(* com.abc.service.*.many*(..))")
public void releaseResource(JoinPoint point) {
System.out.println("@After:模擬釋放資源...");
System.out.println("@After:目標方法爲:" +
point.getSignature().getDeclaringTypeName() +
"." + point.getSignature().getName());
System.out.println("@After:參數爲:" + Arrays.toString(point.getArgs()));
System.out.println("@After:被織入的目標對象爲:" + point.getTarget());
}
}
訪問目標方法最簡單的作法是定義加強處理方法時,將第一個參數定義爲JoinPoint類型,當該加強處理方法被調用時,該JoinPoint參數就表明了織入加強處理的鏈接點。JoinPoint裏包含了以下幾個經常使用的方法:
Object[] getArgs:返回目標方法的參數
Signature getSignature:返回目標方法的簽名
Object getTarget:返回被織入加強處理的目標對象
Object getThis:返回AOP框架爲目標對象生成的代理對象
注意:當使用@Around處理時,咱們須要將第一個參數定義爲ProceedingJoinPoint類型,該類是JoinPoint的子類。