成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Java設(shè)計模式之代理模式

ZHAO_ / 759人閱讀

摘要:設(shè)計模式之代理模式今天學(xué)到的動態(tài)代理實現(xiàn),對代理這個概念很模糊,看了一篇文章發(fā)現(xiàn)這是一種設(shè)計模式,于是學(xué)習(xí)記錄一下。簡介代理模式是一種對象結(jié)構(gòu)型的模式,主要為其他對象提供一種代理以控制對這個對象的訪問。下面依次講解著三種代理。

設(shè)計模式之代理模式

今天學(xué)到Spring的動態(tài)代理實現(xiàn)AOP,對代理這個概念很模糊,看了一篇文章發(fā)現(xiàn)這是一種設(shè)計模式,于是學(xué)習(xí)記錄一下。

簡介

代理模式是一種對象結(jié)構(gòu)型的模式,主要為其他對象提供一種代理以控制對這個對象的訪問。簡單點說就是你訪問一個對象并不是直接的訪問它,而是通過一個代理簡介訪問,那么這個代理就可以在訪問對象之前或之后做一些定制化的操作,比如校驗入?yún)?,打印日志什么的。Spring AOP就是一個代理模式的典型應(yīng)用。

java中的代理分為三類:靜態(tài)代理、動態(tài)代理和Cglib代理。下面依次講解著三種代理。

1. 靜態(tài)代理

靜態(tài)代理在使用時,需要定義接口或者父類,被代理的對象和代理對象需要一起實現(xiàn)同一個接口或者繼承同一個父類。

代碼示例

接口:

package com.wangjun.designPattern.proxy;

/*
 * 我們有一個人類的接口,有很多種職業(yè),比如教師,學(xué)生
 */
public interface Person {
    //獲取本職業(yè)的職責(zé)
    public String getDuty();
}

目標(biāo)對象1:

package com.wangjun.designPattern.proxy;

public class Student implements Person {

    @Override
    public String getDuty() {
        return "學(xué)習(xí)知識";
    }

}

目標(biāo)對象2:

package com.wangjun.designPattern.proxy;

public class Teacher implements Person {

    @Override
    public String getDuty() {
        return "教書育人";
    }

}

代理對象:

package com.wangjun.designPattern.proxy;

import java.util.HashMap;
import java.util.Map;

/*
 * 通過代理,加入緩存功能
 */
public class CachedPersonProxy implements Person{

    private Person person;
    private Map map = new HashMap<>();;

    public CachedPersonProxy(Person person) {
        this.person = person;
    }

    @Override
    public String getDuty() {
        String duty = map.get(person);
        if(null == duty) {
            duty = person.getDuty();
            map.put(person, duty);
        }
        return duty;
    }
}

測試類:

package com.wangjun.designPattern.proxy;

public class Main {

    public static void main(String[] args) {
        Teacher teacher = new Teacher();

        CachedPersonProxy proxy = new CachedPersonProxy(teacher);

        System.out.println(proxy.getDuty());
    }

}

靜態(tài)代理總結(jié):

優(yōu)點:可以做到在不修改目標(biāo)對象的功能前提下,對目標(biāo)功能擴展;

缺點:因為代理對象需要與目標(biāo)對象實現(xiàn)一樣的接口,所以會有很多代理類,同時,一旦接口增加方法,目標(biāo)對象與代理對象都要維護(hù)。

2. 動態(tài)代理

動態(tài)代理也叫JDK代理或者接口代理。

動態(tài)代理有以下特點:

代理對象不需要實現(xiàn)接口;

代理對象的生成是利用JDK中的API動態(tài)的在內(nèi)存中構(gòu)建代理對象(需要我們指定創(chuàng)建代理對象/目標(biāo)對象實現(xiàn)的接口的類型);

代理類所在的包是:java.lang.reflect.Proxy

JDK實現(xiàn)動態(tài)代理只需要使用newProxyInstance方法,該方法需要傳入三個變量:

public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) throws IllegalArgumentException

ClassLoader loader:指定當(dāng)前目標(biāo)對象使用類加載器,獲取加載器的方法是固定的

Class[] interfaces:目標(biāo)對象實現(xiàn)的接口的類型,使用泛型方式確認(rèn)類型

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

代碼示例

接口類Person.class和實現(xiàn)類Teacher.class、Sutdent.class不變,在這個基礎(chǔ)上,增加一個代理工廠類ProxyFactory.java,然后在測試類(需要使用到代理的代碼)中先建立目標(biāo)對象和代理對象的聯(lián)系,接著代用代理對象的中同名方法。

代理工廠類:

package com.wangjun.designPattern.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

public class ProxyFactory {

    private Person person;
    private Map map = new HashMap<>();

    public ProxyFactory(Person person) {
        this.person = person;
    }

    public Object getProxyInstance() {
        return Proxy.newProxyInstance(
                person.getClass().getClassLoader(), 
                person.getClass().getInterfaces(),
                new InvocationHandler() {

                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        String duty = map.get(person);
                        if(null == duty) {
                            //執(zhí)行對象方法
                            System.out.println("沒有緩存");
                            duty = (String) method.invoke(person, args);
                            map.put(person, duty);
                        }
                        return duty;
                    }
                });
    }

}

測試類:

package com.wangjun.designPattern.proxy;

public class Main {

    public static void main(String[] args) {
        Person teacher = new Teacher();
        System.out.println(teacher.getClass());
        //使用動態(tài)代理
        ProxyFactory proxyFactory = new ProxyFactory(teacher);
        Person teacherProxy = (Person) proxyFactory.getProxyInstance();
        System.out.println(teacherProxy.getClass());
        System.out.println(teacherProxy.getDuty());
        System.out.println(teacherProxy.getDuty());
    }
}

總結(jié)

代理對象不需要實現(xiàn)接口,但是目標(biāo)對象一定要實現(xiàn)接口,否則不能用動態(tài)代理。

3. Cglib代理

上面的靜態(tài)代理和動態(tài)代理模式都是要求目標(biāo)對象是實現(xiàn)一個接口的目標(biāo)對象,但是有時候目標(biāo)對象只是一個多帶帶的對象,并沒有實現(xiàn)任何的接口,這個時候就可以使用以目標(biāo)對象子類的方式類實現(xiàn)代理,這種方法就叫做:Cglib代理。

Cglib是一個強大的,高性能,高質(zhì)量的Code生成類庫,它可以在運行期擴展Java類與實現(xiàn)Java接口。它廣泛的被許多AOP的框架使用,例如Spring AOP和synaop,為他們提供方法的interception(攔截)。

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

Cglib包的底層是通過使用一個小而塊的字節(jié)碼處理框架ASM來轉(zhuǎn)換字節(jié)碼并生成新的類。不鼓勵直接使用ASM,因為它要求你必須對JVM內(nèi)部結(jié)構(gòu)包括class文件的格式和指令集都很熟悉。

Cglib子類實現(xiàn)代理的方法

需要引入cglib和asm的jar包文件,Spring的核心包里面已經(jīng)包含了此包;

引入jar包后,就可以在內(nèi)存中動態(tài)構(gòu)建子類;

代理的類不能為final,否則報錯;

目標(biāo)對象的方法如果為final/static,那么就不會被攔截,即不會執(zhí)行目標(biāo)對象額外的方法。

代碼示例

目標(biāo)對象類:

package com.wangjun.designPattern.proxy;
/*
 * 目標(biāo)對象,沒有實現(xiàn)任何接口
 */
public class Doctor {
    public String getDuty() {
        return "救死扶傷";
    }
}

Cglib代理工廠類:

package com.wangjun.designPattern.proxy;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/*
 * cglib代理工廠
 * 對Doctor在內(nèi)存中動態(tài)構(gòu)建一個子類對象
 */
public class CglibProxyFactory implements MethodInterceptor {

    private Object person;
    private Map map = new HashMap<>();

    public CglibProxyFactory(Object person) {
        this.person = person;
    }

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

    @Override
    public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
        String duty = map.get(person);
        if(null == duty) {
            //執(zhí)行目標(biāo)對象的方法
            System.out.println("cglib實現(xiàn),有緩存");
            duty = (String) arg1.invoke(person, arg2);
            map.put(person, duty);
        }
        return duty;
    }

}

測試類:

package com.wangjun.designPattern.proxy;

public class Main {

    public static void main(String[] args) {
        // 使用cglib
        // 目標(biāo)對象
        Doctor target = new Doctor();
        System.out.println(target.getClass());
        // 代理對象
        Doctor proxyCglib = (Doctor) new CglibProxyFactory(target).getProxyInstance();
        // 執(zhí)行代理對象的方法
        System.out.println(proxyCglib.getClass());
        System.out.println(proxyCglib.getDuty());
        System.out.println(proxyCglib.getDuty());
    }
}

在Spring的AOP編程中:

如果加入容器的目標(biāo)對象有實現(xiàn)接口,用JDK代理

如果目標(biāo)對象沒有實現(xiàn)接口,用Cglib代理

參考:https://www.cnblogs.com/cenyu/p/6289209.html

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/69278.html

相關(guān)文章

  • 100行代碼讓您學(xué)會JavaScript原生的Proxy設(shè)計模式

    摘要:面向?qū)ο笤O(shè)計里的設(shè)計模式之代理模式,相信很多朋友已經(jīng)很熟悉了。代表當(dāng)前執(zhí)行方法的實例,即方法調(diào)用者。代表具體的方法名稱?,F(xiàn)在我們再次調(diào)用,傳入構(gòu)造器返回的代理對象打印輸出,代理邏輯生效了和的一樣優(yōu)雅地實現(xiàn)了代理設(shè)計模式。 showImg(https://segmentfault.com/img/remote/1460000016760603);面向?qū)ο笤O(shè)計里的設(shè)計模式之Proxy(代理...

    txgcwm 評論0 收藏0
  • 當(dāng)Kotlin邂逅設(shè)計模式代理模式(二)

    摘要:簡述從這篇文章起,我們將繼續(xù)邂逅設(shè)計模式系列篇中的第二篇代理模式。代理模式可以說很多初級中級開發(fā)者迷惑的設(shè)計模式。首先我們需要使用類圖直觀地表示出代理模式思想。所以基于代理模式很輕松就實現(xiàn)。簡述: 從這篇文章起,我們將繼續(xù)Kotlin邂逅設(shè)計模式系列篇中的第二篇代理模式。代理模式可以說很多初級中級開發(fā)者迷惑的設(shè)計模式。但是它確實應(yīng)用很廣,不用多說大家非常熟悉的Retrofit框架,內(nèi)部使用了...

    番茄西紅柿 評論0 收藏0
  • java設(shè)計模式動態(tài)代理

    摘要:場景描述病從口入這句成語告訴我們注意飲食健康,小六同學(xué)想吃蘋果,在吃蘋果之前需要清洗一下蘋果和洗一下手,吃完蘋果后,需要洗一下手保持個人衛(wèi)生十分鐘后。。。動態(tài)代理小六委托管家來代理洗食物和洗手,小六屬于委托對象,管家屬于代理對象。 前言 為了更好的理解代理模式,首先根據(jù)生活中實際場景進(jìn)行模擬,讓我們在生活中去體驗設(shè)計思想的美妙。 場景描述 病從口入這句成語告訴我們注意飲食健康,小六同學(xué)...

    piglei 評論0 收藏0
  • 慕課網(wǎng)_《模式的秘密代理模式》學(xué)習(xí)總結(jié)

    時間:2017年08月28日星期一說明:本文部分內(nèi)容均來自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com教學(xué)源碼:https://github.com/zccodere/s...學(xué)習(xí)源碼:https://github.com/zccodere/s... 第一章:代理模式 1-1 概念介紹 學(xué)習(xí)本課程基礎(chǔ) 面向?qū)ο蟮脑O(shè)計思維 了解多態(tài)的概念 了解反射機制 課程目標(biāo) 代理模式基本概念及分類...

    wow_worktile 評論0 收藏0

發(fā)表評論

0條評論

ZHAO_

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<