AOP概念與執行原理
引言:
AOP指的就是面向切面程式設計,在實際的開發和工作中很多地方都深有體現,比如許可權控制,控制全域性狀態等。接下來會詳細闡述AOP的概念,給出對應的DEMO來深入學習實踐,探討AOP的意義。
技術點:
1、反射(reflect)
在執行狀態中,對於任意一個類,都能夠知道這個類的屬性和方法。對於任意一個物件,都能呼叫它的任意一個方法和屬性(private的方法也可以呼叫,不用覺得封裝就變得沒有意義了,筆者覺得存在就是合理的)。這種動態獲取的資訊以及動態呼叫物件的方法稱為反射。
PS:順便提一個有意思的情況,筆者親身試驗的:比如說在Integer的List中放置一個String是否可以實現呢?在反射就可以實現哦,下面是實現的程式碼:
ArrayList<Integer> list = new ArrayList<Integer>();
Method method = list.getClass().getMethod("add", Object.class);
method.invoke(list, "我是String");
System.out.println(list.get(0));
//列印結果:我是String
以下是反射的一般作用:
在執行時判斷任意一個物件所屬的類
在執行時構造任意一個類的物件
在執行時判斷一個類所具有的成員變數和方法
在執行時呼叫任意一個物件的方法
生成動態代理
面向切面程式設計(AOP)
1、概念:AOP是建立在Java的反射基礎之上,具體是指散落在程式中的公共部分提取出來,做成了切面類,這樣做的好處在於程式碼的可重用。一旦涉及到該功能的需求發生變化,只要修改該程式碼就行。AOP的實現主要是由JDK的動態代理與CGLIB代理。下面會具體介紹這兩種代理。
2、意義:增強類的功能(在目標物件的方法執行之間和執行之後)。
JDK動態代理:
a、先定義一個介面,這個介面中的方法是“目標方法”
package com.brickworkers;
public interface Sky {
public void rain();
}
b、接著寫一個這個介面的具體實現:
package com.brickworkers;
public class SkyImpl implements Sky{
@Override
public void rain() {
System.out.println("it`s raining");
}
}
c、如果要完成動態代理,首先需要定義一個InvocationHandler介面的子類:
package com.brickworkers;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyInvocationHandler implements InvocationHandler {
//目標物件
private Object obj = null;
//獲取目標物件的代理物件
public Object getProxy(Object obj){
this.obj = obj;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
}
//控制執行目標物件的方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("目標物件方法執行之前");
Object result = method.invoke(obj, args);
System.out.println("目標物件方法執行之後");
return result;
}
}
d:JDK動態代理測試類:
package com.brickworkers;
public class ProxyTest {
public static void main(String[] args) {
//例項化InvocationHandler
MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
//生產代理物件
Sky sky = (Sky) myInvocationHandler.getProxy(new SkyImpl());
sky.rain();
}
}
//執行結果: 目標物件方法執行之前
// it`s raining
// 目標物件方法執行之後
看到這裡相信大家和我一樣就很疑惑,為什麼JDK動態代理只能侷限於介面呢?對此,筆者查閱了一些技術文件和JDK動態代理的原始碼,發現在反編譯產生的proxyTest.class中,類的定義如下:
import dynamic.proxy.UserService;
import java.lang.reflect.*;
public final class $ProxyTest extends Proxy
implements Sky
{
......
}
從反編譯的原始碼可以看出,proxyTest繼承了Proxy,然而在Java中只支援單繼承,但是可以實現多個介面,所以JDK動態代理只能侷限於介面。
那麼JDK實現動態代理需要實現類通過介面定義業務方法,對於沒有介面的類,要實現動態代理要怎麼辦呢?這個時候就需要CGLib動態代理啦。
CGLib動態代理:
a、定義一個目標物件:
package com.brickworkers;
public class Color {
public void showColor(){
System.out.println("red");
}
}
b、如果要完成動態代理,首先需要定義一個MethodInterceptor介面的子類:
package com.brickworkers;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class MyCglib implements MethodInterceptor {
//目標物件
private Object obj = null;
public Object getProxy(Object obj){
this.obj = obj;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(obj.getClass());
// 回撥方法
enhancer.setCallback(this);
// 建立代理物件
return enhancer.create();
}
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("目標物件方法執行之前");
Object result = methodProxy.invoke(obj, args);
System.out.println("目標方法執行之後");
return result;
}
}
c、CGLib動態代理測試類:
package com.brickworkers;
public class CGLibTest {
public static void main(String[] args) {
MyCglib myCglib = new MyCglib();
Color color = (Color) myCglib.getProxy(new Color());
color.showColor();
}
}
//執行結果:目標物件方法執行之前
// red
// 目標方法執行之後
最後,還有一點需要注意:因為CGLib動態代理是建立一個子類來實現的,那麼對於繼承的定義,final類是無法進行代理的哦。
相信能看到這裡的,都是和筆者一樣具有很大求知慾的人,望我們一起進步。