亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專(zhuān)欄INFORMATION COLUMN

Java的三種代理模式

Rango / 449人閱讀

Java的三種代理模式

參考:http://www.cnblogs.com/cenyu/...
Java核心技術(shù)原書(shū)第九版6.5節(jié)

為什么使用代理

  我們?cè)趯?xiě)一個(gè)功能函數(shù)時(shí),經(jīng)常需要在其中寫(xiě)入與功能不是直接相關(guān)但很有必要的代 碼,如日志記錄,信息發(fā)送,安全和事務(wù)支持等,這些枝節(jié)性代碼雖然是必要的,但它會(huì)帶來(lái)以下麻煩:

枝節(jié)性代碼游離在功能性代碼之外,它不是函數(shù)的目的,這是對(duì)OO是一種破壞

枝節(jié)性代碼會(huì)造成功能性代碼對(duì)其它類(lèi)的依賴(lài),加深類(lèi)之間的耦合,可重用性降低

從法理上說(shuō),枝節(jié)性代碼應(yīng)該監(jiān)視"著功能性代碼,然后采取行動(dòng),而不是功能性代碼 通知"枝節(jié)性代碼采取行動(dòng),這好比吟游詩(shī)人應(yīng)該是主動(dòng)記錄騎士的功績(jī)而不是騎士主動(dòng)要求詩(shī)人記錄自己的功績(jī)

常見(jiàn)的代理有:

遠(yuǎn)程代理(Remote Proxy):對(duì)一個(gè)位于不同的地址空間對(duì)象提供一個(gè)局域代表對(duì)象,如RMI中的stub

虛擬代理(Virtual Proxy):根據(jù)需要將一個(gè)資源消耗很大或者比較復(fù)雜的對(duì)象,延遲加 載,在真正需要的時(shí)候才創(chuàng)建

保護(hù)代理(Protect or Access Proxy):控制對(duì)一個(gè)對(duì)象的訪(fǎng)問(wèn)權(quán)限。

智能引用(Smart Reference Proxy):提供比目標(biāo)對(duì)象額外的服務(wù)和功能。

定義

  代理(Proxy)是一種設(shè)計(jì)模式,定義:為其他對(duì)象提供一個(gè)代理以控制對(duì)某個(gè)對(duì)象的訪(fǎng)問(wèn),即通過(guò)代理對(duì)象訪(fǎng)問(wèn)目標(biāo)對(duì)象.這樣做的好處是:可以在目標(biāo)對(duì)象實(shí)現(xiàn)的基礎(chǔ)上,增強(qiáng)額外的功能操作,即擴(kuò)展目標(biāo)對(duì)象的功能.
  這里使用到編程中的一個(gè)思想:不要隨意去修改別人已經(jīng)寫(xiě)好的代碼或者方法,如果需改修改,可以通過(guò)代理的方式來(lái)擴(kuò)展該方法
![](http://oo4l9ob6p.bkt.clouddn....
)
  代理模式的關(guān)鍵點(diǎn)是:代理對(duì)象與目標(biāo)對(duì)象.代理對(duì)象是對(duì)目標(biāo)對(duì)象的擴(kuò)展,并會(huì)調(diào)用目標(biāo)對(duì)象

1. 靜態(tài)代理

  靜態(tài)代理在使用時(shí),需要定義接口或者父類(lèi),被代理對(duì)象與代理對(duì)象一起實(shí)現(xiàn)相同的接口或者是繼承相同父類(lèi).
  關(guān)鍵:在編譯期確定代理對(duì)象,在程序運(yùn)行前代理類(lèi)的.class文件就已經(jīng)存在了。
  比如:在代理對(duì)象中實(shí)例化被代理對(duì)象或者將被代理對(duì)象傳入代理對(duì)象的構(gòu)造方法

  例子:
  模擬保存動(dòng)作,定義一個(gè)保存動(dòng)作的接口:IUserDao.java,然后目標(biāo)對(duì)象UserDao.java實(shí)現(xiàn)這個(gè)接口的方法,此時(shí)如果使用靜態(tài)代理方式,就需要在代理對(duì)象(UserDaoProxy.java)中也實(shí)現(xiàn)IUserDao接口.調(diào)用的時(shí)候通過(guò)調(diào)用代理對(duì)象的方法來(lái)調(diào)用目標(biāo)對(duì)象.
  需要注意的是,代理對(duì)象與目標(biāo)對(duì)象要實(shí)現(xiàn)相同的接口,然后通過(guò)調(diào)用相同的方法來(lái)調(diào)用目標(biāo)對(duì)象的方法

接口:IUserDao.java

public interface IUserDao {
    void save();
}

目標(biāo)對(duì)象類(lèi):UserDao.java

public class UserDao implements IUserDao {
    public void save() {
        System.out.println("----已經(jīng)保存數(shù)據(jù)!----");
    }
}

代理對(duì)象:UserDaoProxy.java

public class UserDaoProxy implements IUserDao{
    //接收保存目標(biāo)對(duì)象
    private IUserDao target;
    public UserDaoProxy(IUserDao target){
        this.target=target;
    }

    public void save() {
        System.out.println("開(kāi)始事務(wù)...");
        target.save();//執(zhí)行目標(biāo)對(duì)象的方法
        System.out.println("提交事務(wù)...");
    }
}

測(cè)試類(lèi):App.java

public class App {
    public static void main(String[] args) {
        //目標(biāo)對(duì)象
        UserDao target = new UserDao();

        //代理對(duì)象,把目標(biāo)對(duì)象傳給代理對(duì)象,建立代理關(guān)系
        UserDaoProxy proxy = new UserDaoProxy(target);

        proxy.save();//執(zhí)行的是代理的方法
    }
}
靜態(tài)代理總結(jié):

可以做到在不修改目標(biāo)對(duì)象的功能前提下,對(duì)目標(biāo)功能擴(kuò)展.

缺點(diǎn):
  代理類(lèi)和委托類(lèi)實(shí)現(xiàn)相同的接口,同時(shí)要實(shí)現(xiàn)相同的方法。這樣就出現(xiàn)了大量的代碼重復(fù)。如果接口增加一個(gè)方法,除了所有實(shí)現(xiàn)類(lèi)需要實(shí)現(xiàn)這個(gè)方法外,所有代理類(lèi)也需要實(shí)現(xiàn)此方法。增加了代碼維護(hù)的復(fù)雜度。

動(dòng)態(tài)代理 動(dòng)態(tài)代理有以下特點(diǎn):

在運(yùn)行期,通過(guò)反射機(jī)制創(chuàng)建一個(gè)實(shí)現(xiàn)了一組給定接口的新類(lèi)

在運(yùn)行時(shí)生成的class,必須提供一組interface給它,然后該class就宣稱(chēng)它實(shí)現(xiàn)了這些 interface。該class的實(shí) 例可以當(dāng)作這些interface中的任何一個(gè)來(lái)用。但是這個(gè)Dynamic Proxy其實(shí)就是一個(gè)Proxy, 它不會(huì)替你作實(shí)質(zhì)性的工作,在生成它的實(shí)例時(shí)你必須提供一個(gè)handler,由它接管實(shí)際的工 作。

動(dòng)態(tài)代理也叫做:JDK代理,接口代理

接口中聲明的所有方法都被轉(zhuǎn)移到調(diào)用處理器一個(gè)集中的方法中處理(InvocationHandler.invoke)。這樣,在接口方法數(shù)量比較多的時(shí)候,我們可以進(jìn)行靈活處理,而不需要像靜態(tài)代理那樣每一個(gè)方法進(jìn)行中轉(zhuǎn)。而且動(dòng)態(tài)代理的應(yīng)用使我們的類(lèi)職責(zé)更加單一,復(fù)用性更強(qiáng)

JDK中生成代理對(duì)象的API
  代理類(lèi)所在包:java.lang.reflect.Proxy
  JDK實(shí)現(xiàn)代理只需要使用newProxyInstance方法,但是該方法需要接收三個(gè)參數(shù),完整的寫(xiě)法是:

static Object newProxyInstance(ClassLoader loader, Class [] interfaces, InvocationHandler handler)

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

ClassLoader loader:指定當(dāng)前目標(biāo)對(duì)象使用類(lèi)加載器,用null表示默認(rèn)類(lèi)加載器

Class [] interfaces:需要實(shí)現(xiàn)的接口數(shù)組

InvocationHandler handler:調(diào)用處理器,執(zhí)行目標(biāo)對(duì)象的方法時(shí),會(huì)觸發(fā)調(diào)用處理器的方法,從而把當(dāng)前執(zhí)行目標(biāo)對(duì)象的方法作為參數(shù)傳入

java.lang.reflect.InvocationHandler:這是調(diào)用處理器接口,它自定義了一個(gè) invoke 方法,用于集中處理在動(dòng)態(tài)代理類(lèi)對(duì)象上的方法調(diào)用,通常在該方法中實(shí)現(xiàn)對(duì)委托類(lèi)的代理訪(fǎng)問(wèn)。

// 該方法負(fù)責(zé)集中處理動(dòng)態(tài)代理類(lèi)上的所有方法調(diào)用。第一個(gè)參數(shù)既是代理類(lèi)實(shí)例,第二個(gè)參數(shù)是被調(diào)用的方法對(duì)象
// 第三個(gè)方法是調(diào)用參數(shù)。
Object invoke(Object proxy, Method method, Object[] args)

代碼示例:
  接口類(lèi)IUserDao.java以及接口實(shí)現(xiàn)類(lèi)UserDao是一樣的.在這個(gè)基礎(chǔ)上,增加一個(gè)代理工廠(chǎng)類(lèi)(ProxyFactory.java),將代理類(lèi)寫(xiě)在這個(gè)地方,然后在測(cè)試類(lèi)中先建立目標(biāo)對(duì)象和代理對(duì)象的聯(lián)系,然后使用代理對(duì)象中的同名方法

代理工廠(chǎng)類(lèi):ProxyFactory.java

/**
 * 創(chuàng)建動(dòng)態(tài)代理對(duì)象
 * 動(dòng)態(tài)代理不需要實(shí)現(xiàn)接口,但是需要指定接口類(lèi)型
 */
public class ProxyFactory{
//維護(hù)一個(gè)目標(biāo)對(duì)象
private Object target;
public ProxyFactory(Object target){
    this.target=target;
}
//給目標(biāo)對(duì)象生成代理對(duì)象
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("開(kāi)始事務(wù)2");
                    //執(zhí)行目標(biāo)對(duì)象方法
                    Object returnValue = method.invoke(target, args);
                    System.out.println("提交事務(wù)2");
                    return returnValue;
                }
            }
    );
}
}

測(cè)試類(lèi):App.java

/**
 * 測(cè)試類(lèi)
*/
public class App {
public static void main(String[] args) {
    // 目標(biāo)對(duì)象
    IUserDao target = new UserDao();
    // 【原始的類(lèi)型 class cn.itcast.b_dynamic.UserDao】
    System.out.println(target.getClass());

    // 給目標(biāo)對(duì)象,創(chuàng)建代理對(duì)象
    IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
    // class $Proxy0   內(nèi)存中動(dòng)態(tài)生成的代理對(duì)象
    System.out.println(proxy.getClass());

    // 執(zhí)行方法   【代理對(duì)象】
    proxy.save();
  }
}

總結(jié):
  代理對(duì)象不需要實(shí)現(xiàn)接口,但是目標(biāo)對(duì)象一定要實(shí)現(xiàn)接口,否則不能用動(dòng)態(tài)代理

Cglib代理

  上面的靜態(tài)代理和動(dòng)態(tài)代理模式都是要求目標(biāo)對(duì)象實(shí)現(xiàn)一個(gè)接口或者多個(gè)接口,但是有時(shí)候目標(biāo)對(duì)象只是一個(gè)多帶帶的對(duì)象,并沒(méi)有實(shí)現(xiàn)任何的接口,這個(gè)時(shí)候就可以使用構(gòu)建目標(biāo)對(duì)象子類(lèi)的方式實(shí)現(xiàn)代理,這種方法就叫做:Cglib代理
  Cglib代理,也叫作子類(lèi)代理,它是在內(nèi)存中構(gòu)建一個(gè)子類(lèi)對(duì)象從而實(shí)現(xiàn)對(duì)目標(biāo)對(duì)象功能的擴(kuò)展.

Cglib是一個(gè)強(qiáng)大的高性能的代碼生成包,它可以在運(yùn)行期擴(kuò)展java類(lèi)與實(shí)現(xiàn)java接口.它廣泛的被許多AOP的框架使用,例如Spring AOP和synaop,為他們提供方法的interception(攔截)

Cglib包的底層是通過(guò)使用字節(jié)碼處理框架ASM來(lái)轉(zhuǎn)換字節(jié)碼并生成新的子類(lèi).

代理的類(lèi)不能為final,否則報(bào)錯(cuò);目標(biāo)對(duì)象的方法如果為final/static,那么就不會(huì)被攔截,即不會(huì)執(zhí)行目標(biāo)對(duì)象額外的業(yè)務(wù)方法.

代碼示例:
目標(biāo)對(duì)象類(lèi):UserDao.java

/**
 * 目標(biāo)對(duì)象,沒(méi)有實(shí)現(xiàn)任何接口
 */
public class UserDao {

    public void save() {
        System.out.println("----已經(jīng)保存數(shù)據(jù)!----");
    }
}

Cglib代理工廠(chǎng):ProxyFactory.java

/**
 * Cglib子類(lèi)代理工廠(chǎng)
* 對(duì)UserDao在內(nèi)存中動(dòng)態(tài)構(gòu)建一個(gè)子類(lèi)對(duì)象
*/
public class ProxyFactory implements MethodInterceptor{
     //維護(hù)目標(biāo)對(duì)象
    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

   //給目標(biāo)對(duì)象創(chuàng)建一個(gè)代理對(duì)象
    public Object getProxyInstance(){
        //1.工具類(lèi)
        Enhancer en = new Enhancer();
       //2.設(shè)置父類(lèi)
        en.setSuperclass(target.getClass());
        //3.設(shè)置回調(diào)函數(shù)
        en.setCallback(this);
        //4.創(chuàng)建子類(lèi)(代理對(duì)象)
        return en.create();
    }

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

測(cè)試類(lèi):

/**
 * 測(cè)試類(lèi)
 */
public class App {

    @Test
    public void test(){
        //目標(biāo)對(duì)象
        UserDao target = new UserDao();

        //代理對(duì)象
        UserDao proxy = (UserDao)new ProxyFactory(target).getProxyInstance();

        //執(zhí)行代理對(duì)象的方法
        proxy.save();
    }
}

AOP(AspectOrientedProgramming):
  將日志記錄,性能統(tǒng)計(jì),安全控制,事務(wù)處理,異常處理等代碼從業(yè)務(wù)邏輯代碼中劃分出來(lái),通過(guò)對(duì)這些行為的分離,我們希望可以將它們獨(dú)立到非業(yè)務(wù)邏輯的方法中,進(jìn)而改變這些行為的時(shí)候不影響業(yè)務(wù)邏輯的代碼---解耦。

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

代理模式與裝飾者模式的區(qū)別

  UML類(lèi)圖基本沒(méi)區(qū)別,都是實(shí)現(xiàn)同一個(gè)接口,一個(gè)類(lèi)包裝另一 個(gè)類(lèi)。 兩者的定義:

裝飾器模式:能動(dòng)態(tài)的新增或組合對(duì)象的行為
在不改變接口的前提下,動(dòng)態(tài)擴(kuò)展對(duì)象的功能

代理模式:為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪(fǎng)問(wèn)
在不改變接口的前提下,控制對(duì)象的訪(fǎng)問(wèn)

  裝飾模式是“新增行為”,而代理模式是“控制訪(fǎng)問(wèn)”。關(guān)鍵就是我們?nèi)绾闻袛嗍恰靶略鲂?為”還是“控制訪(fǎng)問(wèn)”。你在一個(gè)地方寫(xiě)裝飾,大家就知道這是在增加功能,你寫(xiě)代理,大 家就知道是在限制。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/69940.html

相關(guān)文章

  • 淺入淺出Java代理三種實(shí)現(xiàn)

    摘要:代理模式的實(shí)現(xiàn)靜態(tài)代理優(yōu)缺點(diǎn)優(yōu)點(diǎn)只對(duì)對(duì)需要的方法加代理邏輯。通過(guò)繼承的方式進(jìn)行代理,無(wú)論目標(biāo)對(duì)象有沒(méi)有實(shí)現(xiàn)接口都可以代理,但是無(wú)法處理的情況。 注意:本文所有的class使用的static修飾主要是為了能在一個(gè)類(lèi)里面測(cè)試。實(shí)際項(xiàng)目中不應(yīng)該這樣做的,應(yīng)該分包分class。文字描述不是很多,還是看代碼比較好理解吧... 1. Java代理的理解 代理模式是一種設(shè)計(jì)模式,簡(jiǎn)單說(shuō)即是在不改變?cè)?..

    lewif 評(píng)論0 收藏0
  • 面試題:增強(qiáng)一個(gè)對(duì)象的方法三種方式

    摘要:面試題增強(qiáng)一個(gè)對(duì)象的方法的三種方式繼承使用這種方式必須滿(mǎn)足的條件是被增強(qiáng)的方法的所在類(lèi)能被繼承,并且這個(gè)對(duì)象已經(jīng)明確知道。所以創(chuàng)建一個(gè)類(lèi)繼承重寫(xiě)了父類(lèi)的方法增強(qiáng)了,變成飛了。。。 面試題:增強(qiáng)一個(gè)對(duì)象的方法的三種方式 1. 繼承 使用這種方式必須滿(mǎn)足的條件是:被增強(qiáng)的方法的所在類(lèi)能被繼承,并且這個(gè)對(duì)象已經(jīng)明確知道。 舉例: 有一個(gè)接口Person,里面有一個(gè)方法run() pack...

    233jl 評(píng)論0 收藏0
  • 深入理解代理模式

    摘要:代理模式代理類(lèi)中創(chuàng)建一個(gè)真實(shí)對(duì)象的實(shí)例模式的核心裝飾者強(qiáng)調(diào)的是增強(qiáng)自身,在被裝飾之后你能夠在被增強(qiáng)的類(lèi)上使用增強(qiáng)后的功能。 代理模式 在詳細(xì)了解代理模式之前,可能對(duì)于像小秋一樣的小白,只知道一些很淺顯的概念,或者就知道遠(yuǎn)程代理啊,靜態(tài)代理啊,動(dòng)態(tài)代理啊,這些看似可以望文生義的專(zhuān)業(yè)名詞,但是如果我告訴你代理模式貫穿了我們生活的方方面面,就比如你現(xiàn)在刷著公眾號(hào)的時(shí)候,實(shí)際上就用了遠(yuǎn)程代理模...

    testHs 評(píng)論0 收藏0
  • Hibernate最全面試題

    摘要:中怎樣實(shí)現(xiàn)類(lèi)之間的關(guān)系如一對(duì)多多對(duì)多的關(guān)系中怎樣實(shí)現(xiàn)類(lèi)之間的關(guān)系如一對(duì)多多對(duì)多的關(guān)系它們通過(guò)配置文件中的來(lái)實(shí)現(xiàn)類(lèi)之間的關(guān)聯(lián)關(guān)系的。 Hibernate常見(jiàn)面試題 Hibernate工作原理及為什么要用? Hibernate工作原理及為什么要用? 讀取并解析配置文件 讀取并解析映射信息,創(chuàng)建SessionFactory 打開(kāi)Sesssion 創(chuàng)建事務(wù)Transation 持久化操作 提...

    張利勇 評(píng)論0 收藏0
  • 包裝模式就是這么簡(jiǎn)單啦

    摘要:包裝模式是這樣干的首先我們弄一個(gè)裝飾器,它實(shí)現(xiàn)了接口,以組合的方式接收我們的默認(rèn)實(shí)現(xiàn)類(lèi)。其實(shí)裝飾器抽象類(lèi)的作用就是代理核心的功能還是由最簡(jiǎn)單的實(shí)現(xiàn)類(lèi)來(lái)做,只不過(guò)在擴(kuò)展的時(shí)候可以添加一些沒(méi)有的功能而已。 前言 只有光頭才能變強(qiáng) 回顧前面: 給女朋友講解什么是代理模式 前一篇已經(jīng)講解了代理模式了,今天要講解的就是裝飾模式啦~ 在看到FilterInputStream和FilterOutpu...

    Developer 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<