Java動態代理相關簡述

一、概念:

Java動態代理的優勢是實現無侵入式的代碼擴展,也就是方法的增強;讓你可以在不用修改源碼的情況下,增強一些方法;在方法的前後你可以做你任何想做的事情(如Spring AOP、cglib等)。

代理模式:

爲其他對象提供一種代理以控制對這個對象的訪問。在某些情況下,一個對象不適合或者不能直接引用另一個對象,而代理對象可以在客戶端和目標對象之間起到中介的作用。(個人理解就是對調用目標的一種封裝

靜態代理

由程序員創建或者由第三方工具生成,再進行編譯;在程序運行之前,代理類的.class文件已經存在了。
(靜態代理類通常只代理一個類,靜態代理事先知道要代理的是什麼。)

動態代理:

在程序運行時,通過反射機制動態生成。動態代理類通常代理接口下的所有類。( 動態代理事先不知道要代理的是什麼,只有在運行的時候才能確定。 ) 動態代理的調用處理程序必須事先InvocationHandler接口,及使用Proxy類中的newProxyInstance方法動態的創建代理類。JDK動態代理只能代理接口,要代理類需要使用第三方的CLIGB等類庫。

二、JDK動態代理

在這裏插入圖片描述
上面的 JDK Proxy 例子,非常簡單地實現了動態代理的構建和代理操作。
首先,實現對應的 InvocationHandler;
然後,以接口 Hello 爲紐帶,爲被調用目標構建代理對象;
進而應用程序就可以使用代理對象間接運行調用目標的邏輯。
代理爲應用插入額外邏輯(System.out.println("invoke:"))提供了便利的入口。

從 API 設計和實現的角度,這種實現仍然有侷限性,因爲它是以接口爲中心的,相當於添加了一種對於被調用者沒有太大意義的限制。我們實例化的是 Proxy 對象,而不是真正的被調用類型,這在實踐中還是可能帶來各種不便和能力退化。

如果被調用者沒有實現接口,而我們還是希望利用動態代理機制,那麼可以考慮其他方式(如cglib)。

三、cglib動態代理

cglib 動態代理採取的是創建目標類的子類的方式,因爲是子類化,我們可以達到近似使用被調用者本身的效果,克服了接口的依賴。

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @author wangcw
 * @create 2020-01-19 17:05
 * @description:Cglib動態代理
 **/
public class DynamicProxyDemo {

    public static void main(String[] args) {
        HelloCglib helloCglib = new HelloCglib();
        Hello helloProxy = (Hello) helloCglib.getInstance(new Hello());
        helloProxy.sayHello();
    }

    /* 目標類 */
    static class Hello {
        public void sayHello() {
            System.out.println("hello world");
        }
    }

    static class HelloCglib implements MethodInterceptor {

        private Object target;

        public Object getInstance(Object target){
            this.target = target;
            Enhancer enhancer = new Enhancer();
            //設置父類爲目標類
            enhancer.setSuperclass(this.target.getClass());
            // 回調方法
            enhancer.setCallback(this);
            // 創建代理對象
            return enhancer.create();
        }

        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("擴展邏輯 1 - before invoke:");//擴展邏輯
            methodProxy.invokeSuper(o, objects);
            System.out.println("擴展邏輯 2 - after  invoke!");//擴展邏輯
            return null;
        }

    }
    


}

四、優勢比較和應用

JDK Proxy 的優勢:

1、最小化依賴關係,減少依賴意味着簡化開發和維護,JDK 本身的支持,可能比 cglib 更加可靠;
2、平滑進行 JDK 版本升級,而字節碼類庫通常需要進行更新以保證在新版 Java 上能夠使用;
3、代碼實現簡單;
4、新版本JDK也使用ASM提高性能。

基於類似 cglib 框架的優勢:

1、有的時候調用目標可能不便實現額外接口,從某種角度看,限定調用者實現接口是有些侵入性的實踐,類似 cglib 動態代理就沒有這種限制;
2、只操作我們關心的類,而不必爲其他相關類增加工作量;
3、基於ASM字節碼,高性能;
4、通過生成業務類的子類作爲代理類。

動態代理應用非常廣泛,雖然最初多是因爲 RPC 等使用進入我們視線,但是動態代理的使用場景遠遠不僅如此,它完美符合 Spring AOP 等切面編程。簡單來說它可以看作是對 OOP 的一個補充,因爲 OOP 對於跨越不同對象或類的分散、糾纏邏輯表現力不夠,比如在不同模塊的特定階段做一些事情,類似日誌、用戶鑑權、全局性異常處理、性能監控,甚至事務處理等,你可以參考下面這張圖。

在這裏插入圖片描述

發佈了275 篇原創文章 · 獲贊 311 · 訪問量 367萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章