java延遲加載和動態代理小結

延遲加載的核心思想是:如果當前並沒有使用這個組件,則不需要真正地初始化它,使用一個代理對象替代它的原有的位置,只要在真正需要的時候纔對它進行加載。使用代理模式的延遲加載是非常有意義的,首先,它可以在時間軸上分散系統壓力,尤其在系統啓動時,不必完成所有的初始化工作,從而加速啓動時間;其次,對很多真實主題而言,在軟件啓動直到被關閉的整個過程中,可能根本不會被調用,初始化這些數據無疑是一種資源浪費。例如使用代理類封裝數據庫查詢類後,系統的啓動過程這個例子。若系統不使用代理模式,則在啓動時就要初始化 DBRequest對象,而使用代理模式後,啓動時只需要初始化一個輕量級的對象 DBProxy。

下面通過實例簡要說明,方便初步瞭解:

這裏拿數據庫請求爲例:(IDBRequest接口,DBRequest真實類,DBProxy代理)

接口:

public interface IDBRequest {
    public String request();
}

真實類:

public class DBRequest implements IDBRequest{

    public DBRequest(){
        System.out.println("init real class!!");
        try {
            Thread.sleep(1000);
            //數據庫連接操作等
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    @Override
    public String request() {
        
        return "do request";
    }

}
代理類(實現延遲加載)

public class DBProxy implements IDBRequest{

    private DBRequest real=null;
//    protected DBProxy(){
//        System.out.println("init proxy!!");
//    }
    @Override
    public String request() {
        if(real==null){
            real=new DBRequest();//延遲代理,真真在使用的時候初始化等
        }
       
        return real.request();
    }

}

測試類:

public class Test {

    public static void main(String[] args) {
        IDBRequest request=new DBProxy();//這裏不是真實初始化
        request.request();//延遲加載,這裏纔是初始化
        //使用動態代理生成
    }
}

這裏測試沒有調用具體方法,不執行實例化對象這些操作,只有當調用方法時候才實例化對象,這就是使用代理來進行延遲加載的優點,多用於哪些初始化工作大或初始任務佔用資源的情景。

2、動態代理

動態代理是指在運行時動態生成代理類。即,代理類的字節碼將在運行時生成並載入當前代理的 ClassLoader。與靜態處理類相比,動態類有諸多好處。首先,不需要爲真實主題寫一個形式上完全一樣的封裝類,假如主題接口中的方法很多,爲每一個接口寫一個代理方法也很麻煩。如果接口有變動,則真實主題和代理類都要修改,不利於系統維護;其次,使用一些動態代理的生成方法甚至可以在運行時制定代理類的執行邏輯,從而大大提升系統的靈活性。

動態代理實現由多種方式,比如cglib javaassist或jdk自帶的

下面(jdk自帶)繼續上例子,接口和真實類就是上面的,動態代理類(DBRequestHandle)

public class DBRequestHandle implements InvocationHandler{

    Object tar=null;//定義主題接口
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        Object result=null;
        result=method.invoke(tar, args);
        return result;
    }
    public Object bind(Object tar){
        this.tar=tar;
        return Proxy.newProxyInstance(tar.getClass().getClassLoader(), tar.getClass().getInterfaces(), this);
    }

}

實現InvocationHandler即可;主題傳入object,bind方法完成對主題對象綁定,然後具體調用invoke,這樣就完成動態代理;這樣好處是當目標方法增大時,不需要重寫多種方法,一切調用委託給動態代理完成,只需要使用方法時傳入目標對象即可。

public class Test {

    public static void main(String[] args) {
        //IDBRequest request=new DBProxy();//這裏不是真實初始化
        //request.request();//延遲加載,這裏纔是初始化
        
        //使用動態代理生成
        DBRequestHandle proxy=new DBRequestHandle();//init proxy
        IDBRequest handle=(IDBRequest)proxy.bind(new DBRequest());//綁定對象
        handle.request();
    }
}

看完代碼,現在我來回答,動態代理的作用是什麼:

    Proxy類的代碼量被固定下來,不會因爲業務的逐漸龐大而龐大;
    可以實現AOP編程,實際上靜態代理也可以實現,總的來說,AOP可以算作是代理模式的一個典型應用;
    解耦,通過參數就可以判斷真實類,不需要事先實例化,更加靈活多變。


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