1. 程式人生 > >Spring AOP底層實現- JDK動態代理和CGLIB動態代理

Spring AOP底層實現- JDK動態代理和CGLIB動態代理

Spring AOP是執行時織入的,那麼執行時織入到底是怎麼實現的呢?答案就是代理物件。
代理又可以分為靜態代理和動態代理。

靜態代理:由程式設計師建立或特定工具自動生成原始碼,再對其編譯。在程式執行前,代理類的.class檔案就已經存在了。
動態代理:在程式執行時,運用反射機制動態建立而成。

靜態代理的每一個代理類只能為一個介面服務,這樣一來程式開發中必然會產生過多的代理,而且,所有的代理操作除了呼叫的方法不一樣之外,其他的操作都一樣,則此時肯定是重複程式碼。解決這一問題最好的做法是可以通過一個代理類完成全部的代理功能,那麼此時就必須使用動態代理完成。

動態代理 與靜態代理類對照的是動態代理類,動態代理類的位元組碼在程式執行時由Java反射機制動態生成,無需程式設計師手工編寫它的原始碼。動態代理類不僅簡化了程式設計工作,而且提高了軟體系統的可擴充套件性,因為Java 反射機制可以生成任意型別的動態代理類。java.lang.reflect 包中的Proxy類和InvocationHandler 介面提供了生成動態代理類的能力。

Spring AOP使用動態代理技術在執行期間織入增強的程式碼,主要有兩種代理機制:基於JDK的動態代理;基於CGLib的動態代理。JDK本身只提供介面的代理,而不支援類的代理。

代理模式

首先我們來了解代理模式的基本定義。
代理模式的英文叫做Proxy,就是一個人或者一個機構代表另一個人或者另一個機構採取行動。在一些情況下,一個客戶不想或者不能夠直接引用一個物件,而代理物件可以在客戶端和目標物件之間起到中介的作用 。
這裡寫圖片描述

//Subject介面
public interface Subject {
    void request();
}
//目標物件RealSubject
public class RealSubject implements Subject{ @Override public void request() { System.out.println("real subject execute request"); } }
//Proxy代理類
public class Proxy implements Subject{

    private RealSubject realSubject;

    public Proxy(RealSubject realSubject) {
        this
.realSubject = realSubject; } @Override public void request() { System.out.println("before"); try{ realSubject.request(); }catch (Exception e){ System.out.println("ex:"+e.getMessage()); throw e; }finally { System.out.println("after"); } } }
//Client客戶端
public class Client {
    public static void main(String[] args){
        Subject subject = new Proxy(new RealSubject());
        subject.request();
    }
}

這樣就會輸出:

before
real subject execute request
after

是不是達到和AOP一樣的效果了呢?AOP將真正要執行的程式碼交給RealSubject來執行,然後通過proxy來對額外的程式碼進行織入。

動態代理

上面的案例就是一個典型的靜態代理的案例,這樣有什麼缺點呢?
如果當你要代理的方法越多時,你需要重複的邏輯就越多,假設你的目標類有100個方法,那麼你的代理類就需要對這100個方法進行委託,但是又可能他們前後需要執行的邏輯時一樣的,這樣就會產生很多冗餘。
這樣,就有個更好的 動態代理的方法出現了。

動態代理也分為兩類:基於介面的代理和基於繼承的代理
兩類實現的代表是:JDK代理 與 CGlib代理

JDK代理模式

JDK動態代理主要涉及java.lang.reflect包下的兩個類:Proxy類和InvocationHandler介面。
JDK代理實現的三個要點:

  1. 通過java.lang.reflect.Proxy類來動態生成代理類
  2. 代理類要實現InvocationHandler介面
  3. JDK代理只能基於介面進行動態代理的
//客戶端Client
public class Client {
    /*
    *newProxyInstance方法引數解析
    *ClassLoader loader:類載入器 
    *Class<?>[] interfaces:得到全部的介面 
    *InvocationHandler h:得到InvocationHandler介面的子類例項 
    */
    public static void main(String[] args){
        Subject subject = (Subject) Proxy.newProxyInstance(Client.class.getClassLoader(),new Class[]{Subject.class},new JdkProxySubject(new RealSubject()));
        subject.hello();
        subject.request();
    }
}
//代理類JdkProxySubject
public class JdkProxySubject implements InvocationHandler{

    private RealSubject realSubject;

    public JdkProxySubject(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    /*
    *invoke方法方法引數解析
    *Object proxy:指被代理的物件。 
    *Method method:要呼叫的方法 
    *Object[] args:方法呼叫時所需要的引數 
    *InvocationHandler介面的子類可以看成代理的最終操作類。
    */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before");
        Object result = null;
        try{
            //利用反射動態的來反射方法,這就是動態代理和靜態代理的區別
            result = method.invoke(realSubject,args);
        }catch (Exception e){
            System.out.println("ex:"+e.getMessage());
            throw e;
        }finally {
            System.out.println("after");
        }
        return result;
    }
}
//目標物件RealSubject
public class RealSubject implements Subject{
    @Override
    public void request() {
        System.out.println("real subject execute request");
    }

    @Override
    public void hello() {
        System.out.println("hello");
    }
}
//subject介面,這個是jdk動態代理必須的前提。
public interface Subject {
    void request();
    void hello();
}

輸出

before
hello
after
before
real subject execute request
after

我們在subject介面中新增加了一個hello()方法,然後再RealSubject中對hello()方法進行實現,但是在代理類中,我們不需要再去為hello方法再去寫一個代理方法,而是通過反射呼叫目標物件的方法,來動態的生成代理類。

總結:

1、因為利用JdkProxySubject生成的代理類實現了介面,所以目標類中所有的方法在代理類中都有。
2、生成的代理類的所有的方法都攔截了目標類的所有的方法。而攔截器中invoke方法的內容正好就是代理類的各個方法的組成體。
3、利用JDK代理方式必須有介面的存在。

CGlib代理模式

CGLib採用非常底層的位元組碼技術,可以為一個類建立子類,並在子類中採用方法攔截的技術攔截所有的父類方法的呼叫,並順勢織入橫切邏輯。
CGlib和JDK的原理類似,也是通過方法去反射呼叫目標物件的方法。

//客戶端
public class Client {
    public static void main(String[] args){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(RealSubject.class);
        enhancer.setCallback(new DemoMethodInterceptor());
        // 此刻,realSubject不是單純的目標類,而是增強過的目標類  
        RealSubject realSubject = (RealSubject) enhancer.create();
        realSubject.hello();
        realSubject.request()
    }
}
//代理物件
public class DemoMethodInterceptor implements MethodInterceptor{
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("before in cglib");
        Object result = null;
        try{
            result = proxy.invokeSuper(obj, args);
        }catch (Exception e){
            System.out.println("get ex:"+e.getMessage());
            throw e;
        }finally {
            System.out.println("after in cglib");
        }
        return result;
    }
}
//目標物件RealSubject,cglib不需要定義目標類的統一介面
public class RealSubject {

    public void request() {
        System.out.println("real subject execute request");
    }

    public void hello() {
        System.out.println("hello");
    }
}

輸出:

before in cglib
hello
after in cglib
before in cglib
real subject execute request
after in cglib

Spring兩種代理方式

若目標物件實現了介面,spring預設使用JDK的動態代理。
優點:因為有介面,所以使系統更加鬆耦合
缺點:為每一個目標類建立介面

若目標物件沒有實現任何介面,spring使用CGLIB進行動態代理。
優點:因為代理類與目標類是繼承關係,所以不需要有介面的存在。
缺點:因為沒有使用介面,所以系統的耦合性沒有使用JDK的動態代理好。

若目標物件實現了介面,但是強制cglib代理,則使用cglib代理

@SpringBootApplication
//強制使用cglib代理
@EnableAspectJAutoProxy(proxyTargetClass = tree)
public class AopDemoApplication{
    public static void main(String[] args){
        SpringApplication.run(AopDemoApplication.class,args);
    }
}

相關推薦

Spring AOP底層實現- JDK動態代理CGLIB動態代理

Spring AOP是執行時織入的,那麼執行時織入到底是怎麼實現的呢?答案就是代理物件。 代理又可以分為靜態代理和動態代理。 靜態代理:由程式設計師建立或特定工具自動生成原始碼,再對其編譯。在程式執行前,代理類的.class檔案就已經存在了。

Spring底層AOP的原理示例(JDK動態代理cglib動態代理

1 JDK動態代理(必須要有介面) 介面 package com.itykd.dao; public interface UserDao { void save(); void update(); void find(); void delete(); } 實現

Spring AOP之---基於JDK動態代理CGLib動態代理AOP實現

AOP(面向切面程式設計)是OOP的有益補充,它只適合那些具有橫切邏輯的應用場合,如效能監測,訪問控制,事物管理,日誌記錄等。至於怎麼理解橫切邏輯,敲完例項程式碼也就明白了。 為什麼要使用AOP,舉個栗子:需要監測一些方法的執行所消耗的時間,在每個方法開始

JDK動態代理CGLIB動態代理,實現Spring註解管理事務區別。

註解式事務配置 1.JDK動態代理 <tx:annotation-driven transaction-manager="txManager"/>  預設啟用JDK動態代理,JDK只能代理介面不能代理類。 @Transactional註解可以標註在

Java框架學習_Spring(三)Spring_AOP底層實現JDK動態代理Cglib動態代理

AOP和IOC是Spring的兩大思想,AOP即面向切面程式設計,和OOP相輔相成,具體請看: AOP(面向切面程式設計) 這裡學習一下它的底層實現方法----動態代理,動態代理關鍵的是代理,就像你去公司辦事,你有什麼需求,不可能直接找到 boss(原始碼),而是通過祕書(代理)來實現你

spring aop原理 JDK動態代理CGLIB動態代理

lan ble -- 自定義 and ets spec gen ase Spring的兩大特性是IOC和AOPIOC負責將對象動態的註入到容器,從而達到一種需要誰就註入誰,什麽時候需要就什麽時候註入的效果。理解spring的ioc也很重要。但是今天主要來和大家講講aop。A

AOPJDK動態代理CGLib動態代理

測試結果 edit print handle es2017 brush 類庫 構建 sets 一、JDK動態代理 JDK內置的Proxy動態代理可以在運行時動態生成字節碼,而沒必要針對每個類編寫代理類。中間主要使用到了一個接口InvocationHandler與Proxy

Spring的兩種代理方式:JDK動態代理CGLIB動態代理

轉自 :https://blog.csdn.net/cckevincyh/article/details/54962920   代理模式 代理模式的英文叫做Proxy或Surrogate,中文都可譯為”代理“,所謂代理,就是一個人或者一個機構代表另一個人或者另一個機構採取行動。

Spring JDK動態代理CGLIB動態代理

的雙方各和進口量認同感和基你妹, 狂歡節空虛,嗎了 離開了是發;是否  進口量嗎, 的雙方各和進口量認同感和基你妹, 狂歡節空虛,嗎了 離開了是發;是否  進口量嗎, 的雙方各和進口量認同感和基你妹, 狂歡節空虛,嗎了 離開了是發;是否  進口量嗎, 

Spring 靜態代理+JDK動態代理CGLIB動態代理

代理分為兩種:靜態代理  動態代理 靜態代理:本質上會在硬碟上建立一個真正的物理類 動態代理:本質上是在記憶體中構建出一個類。 如果多個類需要進行方法增強,靜態代理則需要建立多個物理類,佔用磁碟空間。而動態代理則是在記憶體中建立,不會對磁碟進行影響。 靜態代理和JDK動態代理需要有介面。  CGLIB

spring AOP 動態代理 jkd動態代理cglib動態代理 hibernate使用cglib延遲載入

spring 的AOP 實現 可以使用jdk的動態代理,也可以使用cglib的動態代理 先說下兩者區別: 靜態代理:代理之前就已經知道了代理者和被代理者 動態代理:代理之前並不清楚,在執行時使用反射機制動態生成代理類的位元組碼 無需我們手動編寫它的原始碼

SSM(六)JDK動態代理Cglib動態代理

sys .com images 織入 load obj spa -1 instance 1.Cglib動態代理 目標類: 1 package cn.happy.proxy.cglib; 2 3 public class Service { 4 publ

03、動態代理--JDK動態代理CGLib動態代理的組合實例

listen -- offer pri eth err imp instance music package com.offer.note.Java基礎.動態代理.CGLib引入增強; public interface Browser { void visitI

jdk動態代理cglib動態代理

java動態代理 分享 運行 相同 ref 面向 () JD 回調方法 參考: http://www.importnew.com/22015.html Java動態代理 上面的代碼運行的結果為: I‘m proxy! Welcome oschina hosee‘s blo

JDK動態代理CGLib動態代理區別

一、概括來說   JDK動態代理只能對實現了介面的類生成代理,而不能針對類   CGLIB是針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的方法(繼承) 二、Spring在選擇用JDK還是CGLiB的依據:    (1)當Bean實現介面時,Spring就

基於JDK動態代理CGLIB動態代理的區別

Spring事務管理,有二種實現方式:xml宣告式事務和註解式事務支援,這裡介紹下,使用註解式事務,使用JDK和CGLIB二種方式的區別: 一、基礎工作 例項SpringMVC + Spring4.3.8 + Mybatis3.2.6 + Logback 的專案,如下所示

關於JDK動態代理cglib動態代理

在spring AOP中,由於通知類中抽取了原始物件中的公共方法,使得原始物件的方法變得不能進行完整的操作。但是我們還是想通過某個方式實現原始物件完成完整操作,我們可以通過為原始物件建立代理物件的方式達到目的,有兩種方式:JDK動態代理和cglib動態代理。 一、JDK動態代理   1、概述:針對記憶體中

Java動態代理JDK介面代理Cglib代理

代理模式 代理模式是常用的java設計模式,它的特徵是代理類與委託類有同樣的介面,代理類主要負責為委託類預處理訊息、過濾訊息、把訊息轉發給委託類,以及事後處理訊息等。代理類與委託類之間通常會存在關聯關係,一個代理類的物件與一個委託類的物件關聯,代理類的物件本身並不真正實現服

jdk動態代理 CGLIB動態代理 詳解

1. 靜態代理模式 //目標介面 public interface IDoSomething { public void doSomething(); }//目標物件 public class DoSomething implements IDoSomething{

Spring AOP底層實現原理

1、spring的AOP底層是由 JDK提供的動態代理技術 和 CGLIB(動態位元組碼增強技術)實現。 2、JDK動態代理:Jdk動態代理只針對於介面操作。 3、CGLIB:可以針