代理模式
代理模式是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提供的方法才能創建代理類的對象
動態代理介紹
- 動態代理是指代理類對象在程序運行時由JVM根據反射機制動態生成的。動態代理不需要定義代理類的,java源文件。
- 動態代理其實就是jdk運行期間,動態創建class字節碼並加載到JVM。
- 動態代理的實現方式常用的有兩種:使用JDK代理,與通過CGLlB動態代理。
動態代理的實現(2種方式)
- jdk動態代理(理解):使用java反射包中的類和接口實現動態代理的功能,反射包java.lang.reflect,里面有三個類:InvocationHandler,Method,Proxy
- cglib動態代理(了解): cglib是第三方的工具庫,創建代理對象
- cglib的原理是繼承,cglib通過繼承目標類,創建它的子類,在子類中重寫父類中同名的方法,實現功能的修改。
- 因為cglib是繼承,重寫方法,所以要求目標類不能是final的,方法也不能是final的。cglib的要求目標類比較寬松,只要能繼承就可以了。cglib在很多的框架中使用,比如mybatis,spring框架中都有使用。
JDK動態代理主要方法說明
jdk動態代理(理解):使用java反射包中的類和接口實現動態代理的功能,反射包java.lang.reflect,里面有三個類:InvocationHandler
、Method
、Proxy
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方法來生成動態代理類!