真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Java中代理模式有什么用

Java中代理模式有什么用,相信很多沒(méi)有經(jīng)驗(yàn)的人對(duì)此束手無(wú)策,為此本文總結(jié)了問(wèn)題出現(xiàn)的原因和解決方法,通過(guò)這篇文章希望你能解決這個(gè)問(wèn)題。

巴東網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián)建站,巴東網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為巴東千余家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)營(yíng)銷網(wǎng)站建設(shè)要多少錢(qián),請(qǐng)找那個(gè)售后服務(wù)好的巴東做網(wǎng)站的公司定做!

代理模式在實(shí)際開(kāi)發(fā)中的遇到的比較多,Spring的AOP還有RPC中用到。學(xué)習(xí)設(shè)計(jì)思想也是很有必要,弄明白其原理,對(duì)日后工作和學(xué)習(xí)中有很大的幫助。
代理模式可以理解為:在不改變?cè)创a的情況下,實(shí)現(xiàn)對(duì)目標(biāo)對(duì)象的功能擴(kuò)展、增強(qiáng)。
代理模式可分為兩種:靜態(tài)代理和動(dòng)態(tài)代理;動(dòng)態(tài)代理有分為JDK代理和cglib代理。

靜態(tài)代理

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

    拿海淘購(gòu)物舉例,我們需要找海淘平臺(tái)讓他們幫我們?cè)诤M馍虉?chǎng)購(gòu)買物美價(jià)廉的商品,然后付款,收貨。代碼如下:

先定義一個(gè)抽象對(duì)象角色。

public interface Item {

    void shopping();
}

目標(biāo)(被代理)對(duì)象角色實(shí)現(xiàn)抽象對(duì)象角色。

public class Person implements Item {

    @Override
    public void shopping() {
        System.out.println("購(gòu)物");
    }
}

代理對(duì)象角色和目標(biāo)(被代理)對(duì)象角色實(shí)現(xiàn)同一接口,代理對(duì)象內(nèi)部含有目標(biāo)(被代理)對(duì)象的引用。

public class PersonProxy implements Item {

    private Person person;

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

    public void begin() {
        System.out.println("登陸海淘平臺(tái),挑選中意的商品");
    }

    public void end() {
        System.out.println("提交訂單,付款,等待收獲");
    }

    @Override
    public void shopping() {
        begin();
        person.shopping();
        end();
    }

}

測(cè)試:

public class Ceshi {


    public static void main(String[] args) {

        Person person = new Person();
        PersonProxy personProxy = new PersonProxy(person);
        personProxy.shopping();

    }
}

運(yùn)行結(jié)果:

登陸海淘平臺(tái),挑選中意的商品
購(gòu)物
提交訂單,付款,等待收獲

Process finished with exit code 0

總結(jié):

    靜態(tài)代理是我們自己寫(xiě)的代理類,是在運(yùn)行前就編譯好的,只能代理某一類情況,擴(kuò)展起來(lái)不方便,需修改代碼,繼續(xù)增加代理類。

動(dòng)態(tài)代理

JDK代理

    代理類在程序運(yùn)行時(shí)創(chuàng)建的代理方式被成為動(dòng)態(tài)代理。 我們上面靜態(tài)代理的例子中,代理類(Proxy)是自己定義好的,在程序運(yùn)行之前就已經(jīng)編譯完成。然而動(dòng)態(tài)代理,代理類并不是在Java代碼中定義的,而是在運(yùn)行時(shí)根據(jù)我們?cè)贘ava代碼中的“指示”動(dòng)態(tài)生成的。相比于靜態(tài)代理, 動(dòng)態(tài)代理的優(yōu)勢(shì)在于可以很方便的對(duì)代理類的函數(shù)進(jìn)行統(tǒng)一的處理,而不用修改每個(gè)代理類中的方法。

    代理類所在包:java.lang.reflect.Proxy,可以看出JDk代理是通過(guò)Java反射實(shí)現(xiàn)的。
    JDK實(shí)現(xiàn)代理只需要使用newProxyInstance方法,但是該方法需要接收三個(gè)參數(shù),完整的寫(xiě)法是:

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

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

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

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

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

代理步驟

  1. 定義一個(gè)事件管理器類實(shí)現(xiàn)invocationHandle接口,并重寫(xiě)invoke(代理類,被代理的方法,方法的參數(shù)列表)方法。 

  2. 實(shí)現(xiàn)被代理類及其實(shí)現(xiàn)的接口。

  3. 調(diào)用Proxy.newProxyInstance(類加載器,類實(shí)現(xiàn)的接口,事務(wù)處理器對(duì)象);生成一個(gè)代理實(shí)例。 

  4. 通過(guò)該代理實(shí)例調(diào)用方法。

創(chuàng)建抽象對(duì)象

public interface Animal {

    void living();

    void eating();
}

創(chuàng)建目標(biāo)(被代理)對(duì)象

public class Person implements Animal {


    @Override
    public void living() {
        System.out.println("談戀愛(ài)");
    }

    @Override
    public void eating() {
        System.out.println("吃早餐");
    }

}

創(chuàng)建代理生成器

public class ProxyInstance implements InvocationHandler {

    private Object target;

    public Object createProxy(Object target) {
        this.target = target;
        Object o = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        return o;
    }

    public void begin() {
        System.out.println("起床");
    }

    public void end() {
        System.out.println("睡覺(jué)");
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        begin();
        Object obj = method.invoke(target, args);
        end();
        return obj;
    }
}

測(cè)試

@Test
public void demo() {
    Person person = new Person();
    Animal proxy = (Animal) new ProxyInstance().createProxy(person);
    proxy.living();
    proxy.eating();
}

結(jié)果

起床
談戀愛(ài)
睡覺(jué)
起床
吃早餐
睡覺(jué)

Process finished with exit code 0

從上看可以看出,JDK代理,可以對(duì)不同的方法進(jìn)行動(dòng)態(tài)的代理增強(qiáng)。(對(duì)eating和living進(jìn)行增強(qiáng)代理,區(qū)別于靜態(tài)代理,需要手動(dòng)去對(duì)不同的方法進(jìn)行增強(qiáng)代理)

我們?cè)僭囈幌缕渌?/p>

public class Cat implements Animal {
    @Override
    public void living() {
        System.out.println("曬太陽(yáng)");
    }

    @Override
    public void eating() {
        System.out.println("吃貓糧");
    }
}


public class Dog implements Animal {
    @Override
    public void living() {
        System.out.println("拆家");
    }

    @Override
    public void eating() {
        System.out.println("吃狗糧");
    }
}

測(cè)試

@Test
public void demo1() {
    Cat cat = new Cat();
    Animal proxy = (Animal) new ProxyInstance().createProxy(cat);
    proxy.living();
    proxy.eating();
}

@Test
public void demo2() {
    Dog dog = new Dog();
    Animal proxy = (Animal) new ProxyInstance().createProxy(dog);
    proxy.living();
    proxy.eating();
}

結(jié)果

起床
曬太陽(yáng)
睡覺(jué)
起床
吃貓糧
睡覺(jué)

Process finished with exit code 0


起床
拆家
睡覺(jué)
起床
吃狗糧
睡覺(jué)

Process finished with exit code 0

從上面可以看出來(lái),JDK代理可以對(duì)不同的類動(dòng)態(tài)的生成代理對(duì)象。

原理:

JDK代理是通過(guò)實(shí)現(xiàn)接口,并通過(guò)反射根據(jù)類名進(jìn)行動(dòng)態(tài)生成代理對(duì)象,并根據(jù)方法名,由動(dòng)態(tài)生成的代理對(duì)象對(duì)相應(yīng)的方法進(jìn)行增強(qiáng)。(可以參考源碼)

cglib代理

    動(dòng)態(tài)代理模式都是要求目標(biāo)對(duì)象是實(shí)現(xiàn)一個(gè)接口的目標(biāo)對(duì)象,但是有時(shí)候目標(biāo)對(duì)象只是一個(gè)單獨(dú)的對(duì)象,并沒(méi)有實(shí)現(xiàn)任何的接口,這個(gè)時(shí)候就可以使用以目標(biāo)對(duì)象子類的方式類實(shí)現(xiàn)代理,這種方法就叫做:cglib代理。

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

  • JDK的動(dòng)態(tài)代理有一個(gè)限制,就是使用動(dòng)態(tài)代理的對(duì)象必須實(shí)現(xiàn)一個(gè)或多個(gè)接口,如果想代理沒(méi)有實(shí)現(xiàn)接口的類,就可以使用cglib實(shí)現(xiàn).

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

  • cglib包的底層是通過(guò)使用一個(gè)小而塊的字節(jié)碼處理框架ASM來(lái)轉(zhuǎn)換字節(jié)碼并生成新的類.不鼓勵(lì)直接使用ASM,因?yàn)樗竽惚仨殞?duì)JVM內(nèi)部結(jié)構(gòu)包括class文件的格式和指令集都很熟悉.

cglib子類代理實(shí)現(xiàn)方法:

1. 需要引入cglib的jar文件,Spring的核心包中已經(jīng)包括了cglib功能。
2. 引入功能包后,就可以在內(nèi)存中動(dòng)態(tài)構(gòu)建子類。
3. 代理的類不能為final,否則報(bào)錯(cuò)。
4. 目標(biāo)對(duì)象的方法如果為final/static,就無(wú)法實(shí)現(xiàn)代理。 

 創(chuàng)建目標(biāo)類,沒(méi)有實(shí)現(xiàn)接口

public class Person {
    public void living() {
        System.out.println("談戀愛(ài)");
    }
}

創(chuàng)建代理對(duì)象

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

import java.lang.reflect.Method;


public class CglibProxy implements MethodInterceptor {
    //目標(biāo)對(duì)象
    private Object target;

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

    //生成代理對(duì)象的方法
    public Object createProxy(){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        Object o = enhancer.create();
        return o;
    }
    
    //在目標(biāo)方法前加強(qiáng)
    public void begin() {
        System.out.println("起床");
    }

    //在目標(biāo)方法后加強(qiáng)
    public void end() {
        System.out.println("睡覺(jué)");
    }


    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        begin();
        //代理執(zhí)行目標(biāo)方法
        Object invoke = method.invoke(target, objects);
        end();
        return invoke;
    }
}

測(cè)試

public class Demo {

    @Test
    public void test(){
        Person p = new Person();
        Person proxy = (Person) new CglibProxy(p).createProxy();
        proxy.living();
    }
}

結(jié)果

起床
談戀愛(ài)
睡覺(jué)

Process finished with exit code 0

再給Person類添加其他方法

public class Person {

    public void living() {
        System.out.println("談戀愛(ài)");
    }

    public void working(){
        System.out.println("去公司上班");
    }
}

測(cè)試

public class Demo {

    @Test
    public void test(){
        Person p = new Person();
        Person proxy = (Person) new CglibProxy(p).createProxy();
        proxy.living();
        proxy.working();
    }
}

結(jié)果

起床
談戀愛(ài)
睡覺(jué)
起床
去公司上班
睡覺(jué)

Process finished with exit code 0

我們?cè)谠囈幌缕渌念?,看看能不能一樣?shí)現(xiàn)代理

public class Cat {

    public void living(){
        System.out.println("曬太陽(yáng)");
    }

    public void working(){
        System.out.println("抓老鼠");
    }
}

測(cè)試

public class Demo {

    @Test
    public void test(){
        Person p = new Person();
        Person proxy = (Person) new CglibProxy(p).createProxy();
        proxy.living();
        proxy.working();
    }

    @Test
    public void test1(){
        Cat cat = new Cat();
        Cat proxy = (Cat) new CglibProxy(cat).createProxy();
        proxy.living();
        proxy.working();
    }
}

結(jié)果

起床
曬太陽(yáng)
睡覺(jué)
起床
抓老鼠
睡覺(jué)

Process finished with exit code 0

看完上述內(nèi)容,你們掌握J(rèn)ava中代理模式有什么用的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!


名稱欄目:Java中代理模式有什么用
網(wǎng)頁(yè)網(wǎng)址:http://weahome.cn/article/pipgsi.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部