AOP爲Aspect Oriented Programming的縮寫,意爲:面向切面編程(也叫面向方面),可以通過預編譯方式和運行期動態代理實現在不修改源代碼的情況下給程序動態統一添加功能的一種技術。AOP實際是GoF設計模式的延續,設計模式孜孜不倦追求的是調用者和被調用者之間的解耦,AOP可以說也是這種目標的一種實現
按自己理解解釋一下這個圖,
AOP是將多個方法中都用到的某部分代碼封裝到SecurityHandler中。要是想把這部分代碼插入到需要的地方,首先我們需要知道在哪些點進行插入。每一個具體的方法對應着的爲joinpoint,而如果是符合某種正則式的方法集則對應着pointcut。在配置時,是不需要配置joinpoint的,但是如果,你想取得你目前正在調用的是哪個方法,則可以用joinpoint獲得。在這裏,我們定義我們要針對哪些方法進行操作。插入嗎,是在方法實現之前插入還是在之後插入呢?這就涉及到advice(具體分爲before advice,after advice,throw advice)。SecurityHandler中代碼注入到具體的方法中的過程則成爲weave。
Aspect(切面):指橫切性關注點的抽象即爲切面,它與類相似,只是兩者的關注點不一樣,類是對物體特徵的抽象,而切面是橫切性關注點的抽象(包括切入點的描述和通知的描述)。
Joinpoint(連接點):所謂連接點是指那些被攔截到的點。在spring中,這些點指的是方法,
因爲spring只支持方法型的連接點,實際上joinpoint還可以是field或者構造器。
Pointcut(切入點):所謂切入點是指我們要對那些joinpoint進行攔截的定義。
Advice(通知):所謂通知是指攔截到jointpoint之後所要做的事情就是通知。通知分爲前置通知、後置通知、異常通知、最終通知、環繞通知。
Target(目標對象):代理的目標對象
Weave(織入):指將aspects應用到target對象並導致proxy對象創建的過程稱爲織入
Introducton(引入):在不修改類代碼的前提下,Introduction可以在運行期爲類動態地添加一些方法或Field
代碼演示:例一採用jpa註解形式
@Aspect
public class SecurityHandler {
/**
* 定義Pointcut,Pointcut的名稱爲addAddMethod(),此方法沒有返回值和參數
* 該方法就是一個標識,不進行調用
*/
@Pointcut("execution(* add*(..))")
privatevoidaddAddMethod(){}
/**
* 定義Advice,表示我們的Advice應用到哪些Pointcut訂閱的Joinpoint上
*/
@Before("addAddMethod()")
//@After("addAddMethod()")
privatevoidcheckSecurity() {
System.out.println("-------checkSecurity-------");
}
}
配置文件需配置:
<!--啓用AspectJ對Annotation的支持 -->
<aop:aspectj-autoproxy/>
<bean id="securityHandler"class="com.bjpowernode.spring.SecurityHandler"/>
例二採用配置文件配置形式:
<bean id="securityHandler"class="com.bjpowernode.spring.SecurityHandler"/>
<aop:config>
<aop:aspectid="securityAspect"ref="securityHandler">
<!--
以add開頭的方法
<aop:pointcut id="addAddMethod" expression="execution(* add*(..))"/>
-->
<!--
com.bjpowernode.spring包下所有的類所有的方法
<aop:pointcut id="addAddMethod" expression="execution(* com.bjpowernode.spring.*.*(..))"/>
-->
<aop:pointcutid="addAddMethod"expression="execution(* com.bjpowernode.spring.*.add*(..)) || execution(* com.bjpowernode.spring.*.del*(..))"/>
<aop:beforemethod="checkSecurity"pointcut-ref="addAddMethod"/>
</aop:aspect>
</aop:config>
Spring
實現AOP是依賴JDK動態代理和CGLIB代理實現的。
JDK動態代理:其代理對象必須是某個接口的實現,它是通過在運行期間創建一個接口的實現類來完成對目標對象的代理。
CGLIB代理:實現原理類似於JDK動態代理,只是它在運行期間生成的代理對象是針對目標類擴展的子類。CGLIB是高效的代碼生成包,底層是依靠ASM(開源的java字節碼編輯類庫)操作字節碼實現的,性能比JDK強。
下面演示動態代理的實現例三:
public class SecurityHandlerimplements InvocationHandler {
private ObjecttargetObject;
public Object createProxyInstance(Object targetObject) {
this.targetObject = targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(),
this);
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
checkSecurity();
//調用目標方法
Object ret = method.invoke(targetObject, args);
return ret;
}
privatevoid checkSecurity() {
System.out.println("-------checkSecurity-------");
}
}
客戶端實現:
public class Client {
publicstaticvoid main(String[] args) {
SecurityHandler hander =new SecurityHandler();
UserManager useraManager = (UserManager)hander.createProxyInstance(new UserManagerImpl());
useraManager.addUser("張三","123");
}
}