亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

首頁 Java Java入門 java的三種代理模式分別是什麼

java的三種代理模式分別是什麼

Jan 30, 2021 am 09:44 AM
java 代理模式

java的三種代理模式分別是什麼

首先來簡單說明一下什麼是代理模式。

代理(Proxy)是一種設(shè)計模式,提供了對目標(biāo)物件另外的存取方式;即透過代理物件存取目標(biāo)物件.這樣做的好處是:可以在目標(biāo)物件實(shí)現(xiàn)的基礎(chǔ)上,增強(qiáng)額外的功能操作,即擴(kuò)展目標(biāo)對象的功能.
這裡使用到編程中的一個思想:不要隨意去修改別人已經(jīng)寫好的代碼或者方法,如果需改修改,可以通過代理的方式來擴(kuò)展該方法

舉個例子來說明代理的作用:假設(shè)我們想邀請一位明星,那麼並不是直接連接明星,而是聯(lián)繫明星的經(jīng)紀(jì)人,來達(dá)到同樣的目的.明星就是一個目標(biāo)對象,他只要負(fù)責(zé)活動中的節(jié)目,而其他瑣碎的事情就交給他的代理人(經(jīng)紀(jì)人)來解決.這就是代理思想在現(xiàn)實(shí)中的一個例子

用圖表示如下:

java的三種代理模式分別是什麼

代理模式的關(guān)鍵點(diǎn)是:代理物件與目標(biāo)物件.代理物件是對目標(biāo)物件的擴(kuò)充,並會呼叫目標(biāo)物件

1.1.靜態(tài)代理

靜態(tài)代理程式在使用時,需要定義介面或父類別,被代理物件與代理物件一起實(shí)作相同的介面或是繼承相同父類別.

下面舉個案例來解釋:
模擬儲存動作,定義一個儲存動作的介面:IUserDao.java,然後目標(biāo)物件實(shí)作這個介面的方法UserDao.java,此時如果使用靜態(tài)代理程式方式,就需要在代理物件(UserDaoProxy.java)中也實(shí)作IUserDao介面.呼叫的時候透過呼叫代理物件的方法來呼叫目標(biāo)物件.
要注意的是,代理物件與目標(biāo)物件要實(shí)現(xiàn)相同的介面,然後透過呼叫相同的方法來呼叫目標(biāo)物件的方法

程式碼範(fàn)例:
介面:IUserDao.java

/**
 * 接口
 */public interface IUserDao {    void save();
}

目標(biāo)物件:UserDao.java

/**
 * 接口實(shí)現(xiàn)
 * 目標(biāo)對象
 */public class UserDao implements IUserDao {    public void save() {
        System.out.println("----已經(jīng)保存數(shù)據(jù)!----");
    }
}

代理物件:UserDaoProxy.java

/**
 * 代理對象,靜態(tài)代理
 */public class UserDaoProxy implements IUserDao{    //接收保存目標(biāo)對象
    private IUserDao target;    public UserDaoProxy(IUserDao target){        this.target=target;
    }    public void save() {
        System.out.println("開始事務(wù)...");
        target.save();//執(zhí)行目標(biāo)對象的方法
        System.out.println("提交事務(wù)...");
    }
}

(學(xué)習(xí)影片分享:java影片教學(xué)

測試類別:App.java

/**
 * 測試類
 */public class App {    public static void main(String[] args) {        //目標(biāo)對象
        UserDao target = new UserDao();        //代理對象,把目標(biāo)對象傳給代理對象,建立代理關(guān)系
        UserDaoProxy proxy = new UserDaoProxy(target);

        proxy.save();//執(zhí)行的是代理的方法
    }
}

靜態(tài)代理程式總結(jié):
1.可以做到在不修改目標(biāo)物件的功能前提下,對目標(biāo)功能擴(kuò)展.
2.缺點(diǎn):

因為代理物件需要與目標(biāo)物件實(shí)現(xiàn)一樣的介面,所以會有很多代理類別,類別太多.同時,一旦介面增加方法,目標(biāo)物件與代理物件都要維護(hù).

如何解決靜態(tài)代理程式中的缺點(diǎn)呢?答案是可以使用動態(tài)代理方式

#1.2.動態(tài)代理

動態(tài)代理有以下特點(diǎn):
1.代理對象,不需要實(shí)現(xiàn)接口
2.代理對象的生成,是利用JDK的API,動態(tài)的在內(nèi)存中構(gòu)建代理對象(需要我們指定創(chuàng)建代理對象/目標(biāo)物件實(shí)現(xiàn)的介面的類型)
3.動態(tài)代理也叫做:JDK代理,介面代理

JDK中產(chǎn)生代理物件的API
代理類別所在套件:java.lang.reflect .Proxy
JDK實(shí)作代理只需要使用newProxyInstance方法,但是該方法需要接收三個參數(shù),完整的寫法是:

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )

注意該方法是在Proxy類別中是靜態(tài)方法,且接收的三個參數(shù)依序為:

ClassLoader loader,:指定目前目標(biāo)物件使用類別載入器,取得載入器的方法是固定的

Class[] interfaces,:目標(biāo)物件實(shí)現(xiàn)的介面的類型,使用泛型方式確認(rèn)類型

InvocationHandler h:事件處理,執(zhí)行目標(biāo)物件的方法時,會觸發(fā)事件處理器的方法,會把目前執(zhí)行目標(biāo)物件的方法作為參數(shù)傳入

程式碼範(fàn)例:
介面類別IUserDao.java以及介面實(shí)作類別,目標(biāo)物件UserDao是一樣的,沒有做修改.在這個基礎(chǔ)上,增加一個代理工廠類別(ProxyFactory.java) ,將代理類別寫在這個地方,然後在測試類別(需要使用到代理的程式碼)中先建立目標(biāo)物件和代理物件的聯(lián)繫,然後代用代理物件的中同名方法

代理工廠類別: ProxyFactory.java

/**
 * 創(chuàng)建動態(tài)代理對象
 * 動態(tài)代理不需要實(shí)現(xiàn)接口,但是需要指定接口類型
 */public class ProxyFactory{    //維護(hù)一個目標(biāo)對象
    private Object target;    public ProxyFactory(Object target){        this.target=target;
    }   //給目標(biāo)對象生成代理對象
    public Object getProxyInstance(){        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),                new InvocationHandler() {                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("開始事務(wù)2");                        //執(zhí)行目標(biāo)對象方法
                        Object returnValue = method.invoke(target, args);
                        System.out.println("提交事務(wù)2");                        return returnValue;
                    }
                }
        );
    }

}

測試類別:App.java

/**
 * 測試類
 */public class App {    public static void main(String[] args) {        // 目標(biāo)對象
        IUserDao target = new UserDao();        // 【原始的類型 class cn.itcast.b_dynamic.UserDao】
        System.out.println(target.getClass());        // 給目標(biāo)對象,創(chuàng)建代理對象
        IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();        // class $Proxy0   內(nèi)存中動態(tài)生成的代理對象
        System.out.println(proxy.getClass());        // 執(zhí)行方法   【代理對象】
        proxy.save();
    }
}

總結(jié):
代理物件不需要實(shí)作介面,但是目標(biāo)物件一定要實(shí)作介面,否則不能用動態(tài)代理

1.3.Cglib代理

上面的靜態(tài)代理和動態(tài)代理模式都是要求目標(biāo)對像是實(shí)現(xiàn)一個接口的目標(biāo)對象,但是有時候目標(biāo)對像只是一個單獨(dú)的對象,並沒有實(shí)現(xiàn)任何的介面,這個時候就可以使用以目標(biāo)物件子類別的方式類別實(shí)作代理,這種方法就叫做:Cglib代理

Cglib代理,也叫作子類代理,它是在內(nèi)存中構(gòu)建一個子類對象從而實(shí)現(xiàn)對目標(biāo)對象功能的擴(kuò)展.

JDK的動態(tài)代理有一個限制,就是使用動態(tài)代理的對象必須實(shí)現(xiàn)一個或多個接口,如果想代理沒有實(shí)現(xiàn)接口的類,就可以使用Cglib實(shí)現(xiàn).Cglib是一個強(qiáng)大的高性能的代碼生成包,它可以在運(yùn)行期擴(kuò)展java類與實(shí)現(xiàn)java接口.它廣泛的被許多AOP的框架使用,例如Spring AOP和synaop,為他們提供方法的interception(攔截)Cglib包的底層是通過使用一個小而塊的字節(jié)碼處理框架ASM來轉(zhuǎn)換字節(jié)碼并生成新的類.不鼓勵直接使用ASM,因為它要求你必須對JVM內(nèi)部結(jié)構(gòu)包括class文件的格式和指令集都很熟悉.

Cglib子類代理實(shí)現(xiàn)方法:
1.需要引入cglib的jar文件,但是Spring的核心包中已經(jīng)包括了Cglib功能,所以直接引入pring-core-3.2.5.jar即可.
2.引入功能包后,就可以在內(nèi)存中動態(tài)構(gòu)建子類
3.代理的類不能為final,否則報錯
4.目標(biāo)對象的方法如果為final/static,那么就不會被攔截,即不會執(zhí)行目標(biāo)對象額外的業(yè)務(wù)方法.

代碼示例:
目標(biāo)對象類:UserDao.java

/**
 * 目標(biāo)對象,沒有實(shí)現(xiàn)任何接口
 */public class UserDao {    public void save() {
        System.out.println("----已經(jīng)保存數(shù)據(jù)!----");
    }
}

Cglib代理工廠:ProxyFactory.java

/**
 * Cglib子類代理工廠
 * 對UserDao在內(nèi)存中動態(tài)構(gòu)建一個子類對象
 */public class ProxyFactory implements MethodInterceptor{    //維護(hù)目標(biāo)對象
    private Object target;    public ProxyFactory(Object target) {        this.target = target;
    }    //給目標(biāo)對象創(chuàng)建一個代理對象
    public Object getProxyInstance(){        //1.工具類
        Enhancer en = new Enhancer();        //2.設(shè)置父類
        en.setSuperclass(target.getClass());        //3.設(shè)置回調(diào)函數(shù)
        en.setCallback(this);        //4.創(chuàng)建子類(代理對象)
        return en.create();

    }    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("開始事務(wù)...");        //執(zhí)行目標(biāo)對象的方法
        Object returnValue = method.invoke(target, args);

        System.out.println("提交事務(wù)...");        return returnValue;
    }
}

測試類:

/**
 * 測試類
 */public class App {    @Test
    public void test(){        //目標(biāo)對象
        UserDao target = new UserDao();        //代理對象
        UserDao proxy = (UserDao)new ProxyFactory(target).getProxyInstance();        //執(zhí)行代理對象的方法
        proxy.save();
    }
}

在Spring的AOP編程中:
如果加入容器的目標(biāo)對象有實(shí)現(xiàn)接口,用JDK代理
如果目標(biāo)對象沒有實(shí)現(xiàn)接口,用Cglib代理

相關(guān)推薦:java入門教程

以上是java的三種代理模式分別是什麼的詳細(xì)內(nèi)容。更多資訊請關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本網(wǎng)站聲明
本文內(nèi)容由網(wǎng)友自願投稿,版權(quán)歸原作者所有。本站不承擔(dān)相應(yīng)的法律責(zé)任。如發(fā)現(xiàn)涉嫌抄襲或侵權(quán)的內(nèi)容,請聯(lián)絡(luò)admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅(qū)動的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費(fèi)的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強(qiáng)大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Laravel 教程
1597
29
PHP教程
1488
72
VSCODE設(shè)置。 JSON位置 VSCODE設(shè)置。 JSON位置 Aug 01, 2025 am 06:12 AM

settings.json文件位於用戶級或工作區(qū)級路徑,用於自定義VSCode設(shè)置。 1.用戶級路徑:Windows為C:\Users\\AppData\Roaming\Code\User\settings.json,macOS為/Users//Library/ApplicationSupport/Code/User/settings.json,Linux為/home//.config/Code/User/settings.json;2.工作區(qū)級路徑:項目根目錄下的.vscode/settings

如何使用JDBC處理Java的交易? 如何使用JDBC處理Java的交易? Aug 02, 2025 pm 12:29 PM

要正確處理JDBC事務(wù),必須先關(guān)閉自動提交模式,再執(zhí)行多個操作,最後根據(jù)結(jié)果提交或回滾;1.調(diào)用conn.setAutoCommit(false)以開始事務(wù);2.執(zhí)行多個SQL操作,如INSERT和UPDATE;3.若所有操作成功則調(diào)用conn.commit(),若發(fā)生異常則調(diào)用conn.rollback()確保數(shù)據(jù)一致性;同時應(yīng)使用try-with-resources管理資源,妥善處理異常並關(guān)閉連接,避免連接洩漏;此外建議使用連接池、設(shè)置保存點(diǎn)實(shí)現(xiàn)部分回滾,並保持事務(wù)盡可能短以提升性能。

Python Itertools組合示例 Python Itertools組合示例 Jul 31, 2025 am 09:53 AM

itertools.combinations用於生成從可迭代對像中選取指定數(shù)量元素的所有不重複組合(順序無關(guān)),其用法包括:1.從列表中選2個元素組合,如('A','B')、('A','C')等,避免重複順序;2.對字符串取3個字符組合,如"abc"、"abd",適用於子序列生成;3.求兩數(shù)之和等於目標(biāo)值的組合,如1 5=6,簡化雙重循環(huán)邏輯;組合與排列的區(qū)別在於順序是否重要,combinations視AB與BA為相同,而permutations視為不同;

在Java的掌握依賴注入春季和Guice 在Java的掌握依賴注入春季和Guice Aug 01, 2025 am 05:53 AM

依賴性(di)IsadesignpatternwhereObjectsReceivedenciesenciesExtern上,推廣looseSecouplingAndEaseerTestingThroughConstructor,setter,orfieldInjection.2.springfraMefringframeWorkSannotationsLikeLikeLike@component@component,@component,@service,@autowiredwithjava-service和@autowiredwithjava-ligatiredwithjava-lase-lightike

Python Pytest夾具示例 Python Pytest夾具示例 Jul 31, 2025 am 09:35 AM

fixture是用於為測試提供預(yù)設(shè)環(huán)境或數(shù)據(jù)的函數(shù),1.使用@pytest.fixture裝飾器定義fixture;2.在測試函數(shù)中以參數(shù)形式註入fixture;3.yield之前執(zhí)行setup,之後執(zhí)行teardown;4.通過scope參數(shù)控製作用域,如function、module等;5.將共用fixture放在conftest.py中實(shí)現(xiàn)跨文件共享,從而提升測試的可維護(hù)性和復(fù)用性。

故障排除常見的java`ofmemoryError`場景'' 故障排除常見的java`ofmemoryError`場景'' Jul 31, 2025 am 09:07 AM

java.lang.OutOfMemoryError:Javaheapspace表示堆內(nèi)存不足,需檢查大對象處理、內(nèi)存洩漏及堆設(shè)置,通過堆轉(zhuǎn)儲分析工具定位並優(yōu)化代碼;2.Metaspace錯誤因類元數(shù)據(jù)過多,常見於動態(tài)類生成或熱部署,應(yīng)限制MaxMetaspaceSize並優(yōu)化類加載;3.Unabletocreatenewnativethread因係統(tǒng)線程資源耗盡,需檢查線程數(shù)限制、使用線程池、調(diào)整棧大??;4.GCoverheadlimitexceeded指GC頻繁但回收少,應(yīng)分析GC日誌,優(yōu)化

如何使用Java的日曆? 如何使用Java的日曆? Aug 02, 2025 am 02:38 AM

使用java.time包中的類替代舊的Date和Calendar類;2.通過LocalDate、LocalDateTime和LocalTime獲取當(dāng)前日期時間;3.使用of()方法創(chuàng)建特定日期時間;4.利用plus/minus方法不可變地增減時間;5.使用ZonedDateTime和ZoneId處理時區(qū);6.通過DateTimeFormatter格式化和解析日期字符串;7.必要時通過Instant與舊日期類型兼容;現(xiàn)代Java中日期處理應(yīng)優(yōu)先使用java.timeAPI,它提供了清晰、不可變且線

Java開發(fā)人員的高級春季數(shù)據(jù)JPA Java開發(fā)人員的高級春季數(shù)據(jù)JPA Jul 31, 2025 am 07:54 AM

掌握AdvancedSpringDataJPA的核心在於根據(jù)場景選擇合適的數(shù)據(jù)訪問方式,並確保性能與可維護(hù)性。 1.自定義查詢中,@Query支持JPQL和原生SQL,適用於復(fù)雜關(guān)聯(lián)與聚合操作,返回結(jié)果建議通過DTO或接口投影(Projection)進(jìn)行類型安全映射,避免使用Object[]帶來的維護(hù)難題。 2.分頁操作需結(jié)合Pageable實(shí)現(xiàn),但要警惕N 1查詢問題,可通過JOINFETCH預(yù)加載關(guān)聯(lián)數(shù)據(jù)或使用投影減少實(shí)體加載,從而提升性能。 3.對於多條件動態(tài)查詢,應(yīng)使用JpaSpecifica

See all articles