靜態代理設計模式

靜態代理設計模式

代理設計模式是在程序開發中使用最多的設計模式,代理設計模式的核心是有真實業務實現類和代理業務實現類,而且代理類要完成比真實業務更多的處理操做。java

傳統代理設計模式的弊端

全部的代理設計模式若是按照設計要求來講,必須是基於接口的設計,也就是說須要首先定義出核心接口的組成。
範例:模擬一個消息發送的代理操做結構(傳統代理設計)設計模式

public class JavaAPIDemo {
    public static void main(String[] args)throws Exception{
        IMessage message=new MessageProxy(new MessageReal());
        message.send();
    }
}
interface IMessage{   //傳統代理設計必須有接口
    public void send();   //業務方法
}
class MessageReal implements IMessage {
    @Override
    public void send() {
        System.out.println("【發送消息】www.mldn.cn");
    }
}
class MessageProxy implements IMessage {   //代理類
    private IMessage message;  //代理對象,必定是業務接口實例
    public MessageProxy(IMessage message){
        this.message=message;
    }
    @Override
    public void send() {
        if(this.connect()){
            this.message.send();  //消息的發送處理
            this.close();
        }
    }
    public boolean connect(){
        System.out.println("【消息代理】進行消息發送通道的鏈接。");
        return true;
    }
    public void close(){
        System.out.println("【消息代理】關閉消息通道。");
    }
}

執行結果:
image.pngide

 

image.png
傳統代理設計this

以上的操做代碼是一個最爲標準的代理設計,可是若是要進一步的去思考會發現客戶端的接口與具體的子類產生了耦合問題,因此這樣的操做若是從實際的開發來說,最好再引入工廠設計模式進行代理對象的獲取。spa

以上的代理設計模式爲靜態代理設計,這種靜態代理涉及的特色在於:一個代理類只爲一個接口服務,若是如今準備有3000個業務接口,則按照此種作法就意味着須要編寫3000個代理類,而且這些代理類操做形式相似。設計

因此如今須要解決的問題在於:如何可讓一個代理類知足於全部的業務接口操做要求。代理

動態代理設計模式

經過靜態代理設計模式的缺陷能夠發現,最好的作法是爲全部功能一致的業務操做接口提供有統一的代理處理操做,而這就能夠經過動態代理機制來實現,可是在動態代理機制中須要考慮到以下幾點問題:code

  • 無論是動態代理類仍是靜態代理類都必定要接收真實業務實現子類對象;
  • 因爲動態代理類再也不與某一個具體的接口進行捆綁,因此應該能夠動態獲取類的接口信息。

 

image.png
動態代理設計模式對象

在進行動態代理實現的操做中,首先須要關注的就是一個InvocationHandler接口,這個接口規定了代理方法的執行。blog

public interface InvocationHandler{
    /**  * 代理方法調用,代理主體類中執行的方法最終都是此方法  * @param proxy 要代理的對象  * @param method 要執行的接口方法名稱  * @param args 傳遞的參數  * @return 某一個方法的返回值  * @throws Throwable 方法調用時出現的錯誤繼續向上拋出  */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

在進行動態代理設計時,對於動態對象的建立是由JVM底層完成的,此時主要依靠的是java.lang.reflect.Proxy程序類,而這個類中只提供了一個核心方法:
代理對象:public static Object newProxyInstance​(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

  • ClassLoader loader:獲取當前真實主體類的ClassLoader;
  • Class<?>[] interfaces:代理是圍繞接口進行的,因此必定要獲取真實主體類的接口信息;
  • InvocationHandler h:代理處理的方法;

 

image.png
代理方法

範例:實現動態代理機制

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JavaAPIDemo {
    public static void main(String[] args)throws Exception{
        IMessage msg=(IMessage)new MLDNProxy().bind(new MessageReal());
        msg.send();
    }
}
class MLDNProxy implements InvocationHandler{
    private Object target;  //保存真實業務對象
    /** * 進行真實業務對象與代理業務對象之間的綁定處理 * @param target 真實業務對象 * @return Proxy生成的代理業務對象 */
    public Object bind(Object target){
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
    }
    public boolean connect(){
        System.out.println("【消息代理】進行消息發送通道的鏈接。");
        return true;
    }
    public void close(){
        System.out.println("【消息代理】關閉消息通道。");
    }
    @Override
    public Object invoke(Object pro, Method method, Object[] args) throws Throwable {
        System.out.println("*****【執行方法: 】"+method);
        Object returnData = null;
        if(this.connect()){
            returnData = method.invoke(this.target, args);
            this.close();
        }
        return returnData;
    }
}
interface IMessage{  //傳統代理設計必須有接口
    void send();  //業務方法
}
class MessageReal implements IMessage {
    @Override
    public void send() {
        System.out.println("【發送消息】www.mldn.cn");
    }
}

執行結果:
image.png

若是認真觀察系統中提供的Proxy.newProxyInstance()方法,會發現該方法會使用大量的底層機制來進行代理對象的動態建立,全部的代理類是符合全部相關功能需求的操做功能類,它再也不表明具體的接口,這樣在處理時就必須依賴於類加載器與接口進行代理對象的僞造。

相關文章
相關標籤/搜索