來,帶你手撕一個AOP

本文主要講的是如何使用JDK動態代理實現簡單的AOP。AOP是啥?若是你想在某些方法執行先後插入一些通用的處理,你能夠考慮AOP。java

預備知識

Proxy

JDK中提供了一個Proxy類用於建立動態代理對象的靜態方法,若是在程序中爲一個或多個接口動態地生成實現類,就能夠使用Proxy來建立動態代理類。 Proxy提供了下面的方法來建立動態代理實例:ide

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)測試

該代理對象的實現類實現了interfaces所指定的系列接口,執行代理對象的每一個方法時都會被替換執行InvocationHandler對象的invoke方法this

InvocationHandler

InvocationHandler是一個接口,在建立動態代理實例的時候須要把一個InvocationHandler的實現類傳進去,那麼執行代理對象的每一個方法時就會被替換成執行InvocationHandler實現類中的invoke方法,至於這個invoke方法要怎麼實現,就由用戶本身決定。spa

反射中Method的invoke()

java.lang.reflect.Method包中有一個方法代理

public Object invoke(Object obj, Object... args)code

該方法能夠實現對象方法的調用,它是Method類的實例方法,該方法中的參數obj是調用方法的對象,args是用於方法調用的參數。對象

實現過程

Pig接口,就定義了兩個方法接口

public interface Pig {

    void info();

    void run();
}
複製代碼

Pig的實現類,咱們要作的就是在這兩個方法執行的先後插入本身一些額外的操做get

public class FatPig implements Pig {

    @Override
    public void info() {
        System.out.println("我是一頭小肥豬!");
    }

    @Override
    public void run() {
        System.out.println("我要跑步啦!");
    }
}
複製代碼

LogUtils,須要在代理對象方法執行先後調用的方法

public class LogUtils {

    public void before() {
        System.out.println("==== 方法開始執行 ====");
    }

    public void after() {
        System.out.println("==== 方法執行結束 ====");
    }

}
複製代碼

PigInvocationHandler,該類實現了InvocationHandler接口。咱們定義了一個Object類型的實例變量,由於咱們須要在invoke方法中調用被代理對象的實現類的對應的方法。在invoke方法中,有兩個關鍵的參數:method表明正在執行的方法,args表明調用目標方法時傳入的實參。而後咱們就能夠在執行代理對象的方法先後自由插入本身的方法了。

public class PigInvocationHandler implements InvocationHandler {

    // 須要被代理的對象
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    // 執行動態代理對象的全部方法時,都會被替換成執行以下的invoke方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        LogUtils logUtils = new LogUtils();
        // 執行logUtils對象中的before方法
        logUtils.before();
        // 以target做爲主調來執行method方法
        Object result = method.invoke(target, args);
        // 執行logUtils對象中的after方法
        logUtils.after();
        return result;
    }
}
複製代碼

測試類

public class MyProxyFactory {

    // 爲指定的target生成動態代理對象
    public static Object getProxy(Object target) {
        PigInvocationHandler handler = new PigInvocationHandler();
        // 爲handler設置target對象
        handler.setTarget(target);
        // 建立並返回一個動態代理
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler);
    }

    public static void main(String[] args) throws Exception {
        // 建立一個原始的FatPig對象,做爲target
        Pig target = new FatPig();
        // 以指定的target來建立動態代理對象
        Pig pig = (Pig) MyProxyFactory.getProxy(target);
        pig.info();
        pig.run();
    }
}
複製代碼

運行結果:

==== 方法開始執行 ====
我是一頭小肥豬!
==== 方法執行結束 ====

==== 方法開始執行 ====
我要跑步啦!
==== 方法執行結束 ====

上面實現了簡單的AOP功能,咱們能夠在invoke方法裏面加上更多的判斷,使得功能更增強大,例如能夠根據method參數指定某些方法先後執行特殊的處理。

相關文章
相關標籤/搜索