java-動態代理


代理模式

代理模式是Java中常用的設計模式,主要由公共接口、被代理類和代理類等三部分組成,代理類持有被代理類的實類,代為執行具體的類方法。其中代理類與被代理類有同樣的接口。

代理類與被代理類之間通常會存在關聯關系,一個代理類的對象與一個被代理類的對象關聯,代理類的對象本身並不真正實現服務,而是通過調用被代理類對象的方法來提供特定的服務。

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

代理模式UML

  • Subject:抽象主題角色,抽象主題類可以是抽象類,也可以是接口,是一個最普通的業務類型定義,無特殊要求。
  • RealSubject:具體主題角色,也叫被委托對象,被代理角色。是業務邏輯的具體執行者
  • Proxy:代理主題角色,也叫委托類、代理類。它把所有抽象主題類定義的方法給具體主題角色實現,並且在具體主題角色處理完畢前后做預處理和善后工作。

代理模式

根據加載被代理類的時機不同,將代理分為靜態代理和動態代理。

靜態代理,程序運行之前就已經存在的編譯好的代理類

動態代理,程序運行時動態生成,根據java的反射機制動態生成

靜態代理

靜態代理:在代碼編譯時就確定了具體的被代理類。由程序員創建或特定工具自動生成源代碼,也就是在編譯時就已經將接口、被代理類、代理類等確定下來。在程序運行之前,代理類的.class文件就已經生成。

代碼案例

//IMacSeller.java
public interface IMacSeller{
  void buy()
}


//USAMacSeller.java
public class USAMacSeller implements IMacSeller{
  @Override
  public void buy(){
    System.out.println("buy a macbook from USA")
  }
}


//HongkongMacSeller.java
public class HongkongMacSeller implements IMacSeller{
  IMacSeller seller =new USAMacSeller();
  @Override
  public void buy(){
    seller.buy();
    System.out.println("buy a macbook from Hongkong");
  }
}


//Client.java
public class Client{
  public static void main(String[] args){
    System.out.println("Proxy main");
    IMacSeller seller = new HongkongMacSeller();
    seller.buy();
  }
}

JAVA動態代理

什么是動態代理

使用jdk的反射機制,創建對象的能力,創建的是代理類的的對象.而不用我們創建類文件,不用寫java文件。什么叫動態?在程序執行時,調用jdk提供的方法才能創建代理類的對象

動態代理介紹

  1. 動態代理是指代理類對象在程序運行時由JVM根據反射機制動態生成的。動態代理不需要定義代理類的,java源文件。
  2. 動態代理其實就是jdk運行期間,動態創建class字節碼並加載到JVM。
  3. 動態代理的實現方式常用的有兩種:使用JDK代理,與通過CGLlB動態代理

動態代理的實現(2種方式)

  1. jdk動態代理(理解):使用java反射包中的類和接口實現動態代理的功能,反射包java.lang.reflect,里面有三個類:InvocationHandler,Method,Proxy
  2. cglib動態代理(了解): cglib是第三方的工具庫,創建代理對象
    1. cglib的原理是繼承,cglib通過繼承目標類,創建它的子類,在子類中重寫父類中同名的方法,實現功能的修改。
    2. 因為cglib是繼承,重寫方法,所以要求目標類不能是final的,方法也不能是final的。cglib的要求目標類比較寬松,只要能繼承就可以了。cglib在很多的框架中使用,比如mybatis,spring框架中都有使用。

JDK動態代理主要方法說明

jdk動態代理(理解):使用java反射包中的類和接口實現動態代理的功能,反射包java.lang.reflect,里面有三個類:InvocationHandlerMethodProxy

1. 反射 (理解反射的method.invoke方法)

Method類,表示方法。類中的方法,通過反射 Method可以執行某個方法

method.invoke() 反射調用方法

2. jdk動態代理的實現

創建動態代理類會使用到java.lang.reflect.Proxy類和java.lang.reflect.InvocationHandler接口。

反射包 java.lang.reflect ,里面有3個類:InvocationHandler,Method,Proxy

java.lang.reflect.Proxy

java.lang.reflect.Proxy主要用於生成動態代理類Class、創建代理類實例,該類實現了java.io.Serializable接口。

創建代理類:Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

java.lang.reflect.Proxy類主要方法如下:

package java.lang.reflect;

import java.lang.reflect.InvocationHandler;

/**
 * Creator: yz
 * Date: 2020/1/15
 */
public class Proxy implements java.io.Serializable {

  // 省去成員變量和部分類方法...

    /**
     * 獲取動態代理處理類對象
     *
     * @param proxy 返回調用處理程序的代理實例
     * @return 代理實例的調用處理程序
     * @throws IllegalArgumentException 如果參數不是一個代理實例
     */
    public static InvocationHandler getInvocationHandler(Object proxy)
            throws IllegalArgumentException {
        ...
    }

    /**
     * 創建動態代理類實例
     *
     * @param loader     指定動態代理類的類加載器
     * @param interfaces 指定動態代理類的類需要實現的接口數組
     * @param h          動態代理處理類
     * @return 返回動態代理生成的代理類實例
     * @throws IllegalArgumentException 不正確的參數異常
     */
    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
            throws IllegalArgumentException {
        ...
    }

    /**
     * 創建動態代理類
     *
     * @param loader     定義代理類的類加載器
     * @param interfaces 代理類要實現的接口列表
     * @return 用指定的類加載器定義的代理類,它可以實現指定的接口
     */
    public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) {
        ...
    }

    /**
     * 檢測某個類是否是動態代理類
     *
     * @param cl 要測試的類
     * @return 如該類為代理類,則為 true,否則為 false
     */
    public static boolean isProxyClass(Class<?> cl) {
        return java.lang.reflect.Proxy.class.isAssignableFrom(cl) && proxyClassCache.containsValue(cl);
    }

    /**
     * 向指定的類加載器中定義一個類對象
     *
     * @param loader 類加載器
     * @param name   類名
     * @param b      類字節碼
     * @param off    截取開始位置
     * @param len    截取長度
     * @return JVM創建的類Class對象
     */
    private static native Class defineClass0(ClassLoader loader, String name, byte[] b, int off, int len);

}

java中要創建一個代理對象,必須調用Proxy類的靜態方法newProInstance,該方法原型如下:

Object Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler handler) throws IllegalArgumentException
  
  
//loader,表示類加載器,對於不同來源(系統庫或網絡等)的類需要不同的類加載器來加載,這是java安全模型的一部分。
//interfaces,它就是被代理類對象的共有的接口
//handler,表示調用處理器,它必須是實現了InvocationHandler接口的對象,其作用是定義代理對象中需要執行的具體操作

java.lang.reflect.InvocationHandler

InvocationHandler 接口只有一個方法invoke,定義了代理對象在執行真實對象的方法時所希望執行的動作

invoke():表示代理對象要執行的功能代碼。你的代理類要完成的功能就寫在invoke中

代理類完成的功能:

1、調用目標方法,執行目標方法的功能

2、功能增強,在目標方法調用時,增加功能

方法原型:

Object invoke(Object proxy,Method method,Object[] args) throws Throwable
  // proxy,jdk創建的代理對象,無需賦值
  // method,目標類中的方法,jdk提供的method對象
  // args,目標類中方法的參數,jdk提供

InvocationHandler接口:表示你的代理要干什么

怎么用:

1.創建類實現接口InvocationHandler

2.重寫invoke()方法,把原來靜態代理中代理類要完成的功能寫到這里

3. JDK動態代理案例

定義接口ImiSeller

package com.tyut.dynamic;

public interface ImiSeller {
    void buy();

}

實現接口的目標實現類Mistore

package com.tyut.dynamic;

public class Mistore implements ImiSeller {
    @Override
    public void buy() {
        System.out.println("通過小米商店買了一部小米手機");
    }
}

定義代理類實現的具體增強類MyHandler,重寫invoke方法,代理類具體執行的方法

package com.tyut.dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyHandler  implements InvocationHandler {
    Object proxyTarget;

    public MyHandler(Object proxyTarget) {
        this.proxyTarget = proxyTarget;
        
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        method.invoke(proxyTarget,args); //個人理解,通過反射調用目標類方法,這里的invoke是反射,上面的invoke是invocationHandler接口的方法
        System.out.println("增強代理方式實現");
        return null;
    }
}

創建代理對象並執行代理方法

package com.tyut.dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class MyApp {
    public static void main(String[] args) {
        // 目標類
        ImiSeller sell = new  Mistore();
      
        //實現InvocationHandle接口中的invoke方法,並將被代理的實例對象傳入,相當於之前的代理類,誰使用它,它就返回誰的對象,
        InvocationHandler myhandler = new MyHandler(sell);
        
      	// 動態生成代理類對象
        // 指定動態代理類的類加載器 sell.getClass().getClassLoader()
        // 定義動態代理類 實現的接口 sell.getClass().getInterfaces()
        // 動態代理處理類
        ImiSeller proxy = (ImiSeller) Proxy.newProxyInstance(sell.getClass().getClassLoader(), sell.getClass().getInterfaces(),myhandler);
        
      //使用生成的代理類,調用invoke中定義的方法
        proxy.buy();
    }
}

通過動態代理就可以動態生成代理類,實現接口InvocationHandler的類(這個實現InvocationHandler的類相當於定義好被代理類的相關操作),最后然后通過Proxy類的newProxyInstance方法來生成動態代理類!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM