亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

JAVA代理,靜態(tài),動(dòng)態(tài)詳解

 更新時(shí)間:2021年09月08日 09:24:31   作者:張小馳出沒(méi)  
這篇文章主要介紹了Java靜態(tài)代理和動(dòng)態(tài)代理總結(jié),非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下,希望能夠給你帶來(lái)幫助

代理

其他對(duì)象提供一種代理以控制這個(gè)對(duì)象的訪(fǎng)問(wèn),在某些情況下一個(gè)對(duì)象不能直接訪(fǎng)問(wèn)那個(gè)對(duì)象時(shí),代理就起到了客戶(hù)端和被代理對(duì)象 (委托類(lèi)) 中介作用。

按照代理的創(chuàng)建時(shí)期,代理類(lèi)可以分為兩種:

靜態(tài):由程序員創(chuàng)建代理類(lèi)或特定工具自動(dòng)生成源代碼再對(duì)其編譯。在程序運(yùn)行前代理類(lèi)的.class文件就已經(jīng)存在了。

動(dòng)態(tài):在程序運(yùn)行時(shí)運(yùn)用反射機(jī)制動(dòng)態(tài)創(chuàng)建而成。

靜態(tài)代理

1

Subject: 代理類(lèi)和被代理類(lèi)實(shí)現(xiàn)同樣的接口

Proxy:代理類(lèi),里面有被代理類(lèi),具體邏輯委托被代理類(lèi)進(jìn)行處理

RealSubject:被代理類(lèi),可以在其內(nèi)做一些訪(fǎng)問(wèn)權(quán)限控制,額外的業(yè)務(wù)處理

Client:看到的是代理類(lèi),并不知道具體處理業(yè)務(wù)邏輯的類(lèi),降低耦合性

代碼實(shí)現(xiàn)

UserDAO 代理和被代理的公共的接口(Subject)

public interface ProxyDao {
    boolean insert(String name);
}

UserDAOImpl 被代理類(lèi)(RealSubject)

public class ProxyDaoImpl implements ProxyDao {
    @Override
    public boolean insert(String name) {
        System.out.println("insert name=" + name);
        return true;
    }
}

ProxyByInterface 代理類(lèi),通過(guò)實(shí)現(xiàn)接口方式實(shí)現(xiàn)代理方式(Proxy)

public class ProxyByInterface implements ProxyDao {
    private ProxyDao proxyDao;
    public ProxyByInterface(ProxyDao proxyDao) {
        this.proxyDao = proxyDao;
    }
    @Override
    public boolean insert(String name) {
        System.out.println("before insert by interface");
        return proxyDao.insert(name);
    }
}

ProxyByExtend 代理類(lèi),通過(guò)繼承被代理類(lèi)實(shí)現(xiàn)的代理方式(Proxy)

public class ProxyByExtend extends ProxyDaoImpl{
    private ProxyDaoImpl proxyDao;
    public ProxyByExtend(ProxyDaoImpl proxyDao) {
        this.proxyDao = proxyDao;
    }
    @Override
    public boolean insert(String name) {
        System.out.println("before insert by extend");
        return proxyDao.insert(name);
    }
}

獲取代理對(duì)象客戶(hù)端(Client)

public class Client {
    public static void main(String[] args) {
        ProxyDaoImpl proxyDao = new ProxyDaoImpl();
        //和被代理類(lèi)實(shí)現(xiàn)同個(gè)接口方式進(jìn)行代理
        ProxyByInterface proxyByInterface = new ProxyByInterface(proxyDao);
        proxyByInterface.insert("zc-Interface");
        //通過(guò)繼承被代理類(lèi)方式進(jìn)行代理
        ProxyByExtend proxyByExtend = new ProxyByExtend(proxyDao);
        proxyByExtend.insert("zc-Extend");
    }
}

2

好處:

可以不用動(dòng)原來(lái)類(lèi)的邏輯,再次增加一些功能,符合開(kāi)閉原則。

真正的業(yè)務(wù)還是交給被代理對(duì)象處理的,無(wú)須修改原來(lái)的類(lèi)就可以使用代理進(jìn)行實(shí)現(xiàn)。

缺點(diǎn):

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

代理對(duì)象只服務(wù)于一種類(lèi)型的對(duì)象,如果要服務(wù)多類(lèi)型的對(duì)象。勢(shì)必要為每一種對(duì)象都進(jìn)行代理,靜態(tài)代理在程序規(guī)模稍大時(shí)就無(wú)法勝任了。

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

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

Jdk動(dòng)態(tài)代理,針對(duì)的是實(shí)現(xiàn)接口的類(lèi)

要求目標(biāo)對(duì)象必須實(shí)現(xiàn)接口,因?yàn)樗鼊?chuàng)建代理對(duì)象的時(shí)候是根據(jù)接口創(chuàng)建的。被代理對(duì)象可以可以實(shí)現(xiàn)多個(gè)接口,創(chuàng)建代理時(shí)指定創(chuàng)建某個(gè)接口的代理對(duì)象就可以調(diào)用該接口定義的方法了。

需要java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy 類(lèi)的支持

//Object proxy:被代理的對(duì)象
//Method method:要調(diào)用的方法
//Object[] args:方法調(diào)用時(shí)所需要參數(shù)
public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
//CLassLoader loader:類(lèi)的加載器
//Class<?> interfaces:得到全部的接口
//InvocationHandler h:得到InvocationHandler接口的子類(lèi)的實(shí)例
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

代碼實(shí)現(xiàn)

NameDao 姓名-接口(Subject)

public interface NameDao {
    public boolean addName(String name);
}

AgeDao 年齡-接口(Subject)

public interface AgeDao {
    public boolean addAge(Integer age);
}

NameAndAgeDaoImpl 姓名、年齡實(shí)現(xiàn)類(lèi)(RealSubject)

public class NameAndAgeDaoImpl implements NameDao,AgeDao {
    @Override
    public boolean addName(String name) {
        System.out.println("NameDaoImpl----->" + name);
        return true;
    }
    @Override
    public boolean addAge(Integer age) {
        System.out.println("AgeDaoImpl----->" + age);
        return true;
    }
}

MyInvocationHandler,對(duì)接口提供的方法進(jìn)行增強(qiáng)(Proxy)

public class MyInvocationHandler implements InvocationHandler {
    private Object target;
    public MyInvocationHandler(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("----------before----------");
        System.out.println("Proxy=" + proxy.getClass());
        System.out.println("method=" + method);
        System.out.println("args=" + Arrays.toString(args));
        //執(zhí)行目標(biāo)方法對(duì)象
        Object result = method.invoke(target, args);
        System.out.println("----------after----------");
        return result;
    }
}

ProxyFactory 代理工廠(chǎng)

public class ProxyFactory {
    public static Object getProxy(Object proxyObj) {
        /**
         * loader 指定加載jvm運(yùn)行時(shí)動(dòng)態(tài)生成的代理對(duì)象的加載器
         * interface 真實(shí)對(duì)象實(shí)現(xiàn)的所有接口
         * h 實(shí)現(xiàn)InvocationHandler接口對(duì)象
         */
      // return Proxy.newProxyInstance(proxyObj.getClass().getClassLoader(),
      // proxyObj.getClass().getInterfaces(), new MyInvocationHandler(proxyObj));
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                proxyObj.getClass().getInterfaces(), new MyInvocationHandler(proxyObj));
    }
    public static void main(String[] args) {
        NameDao nameDao = (NameDao) getProxy(new NameAndAgeDaoImpl());
        AgeDao ageDao = (AgeDao) getProxy(new NameAndAgeDaoImpl());
        nameDao.addName("zc");
        ageDao.addAge(20);
    }
}

3

思考 為什么需要 實(shí)現(xiàn)接口的類(lèi),而不是 類(lèi)

main函數(shù)中,運(yùn)行該語(yǔ)句:

System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
public static void main(String[] args) {
    System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
    NameDao nameDao = (NameDao) getProxy(new NameAndAgeDaoImpl());
    AgeDao ageDao = (AgeDao) getProxy(new NameAndAgeDaoImpl());
    nameDao.addName("zc");
    ageDao.addAge(20);
}

可以查看 $Proxy0 類(lèi):

4

會(huì)發(fā)現(xiàn)他已經(jīng)繼承了 Proxy , 之后才是創(chuàng)建的一個(gè)(多個(gè))接口;而由于java是 單繼承、多接口 的特性,所以JDK動(dòng)態(tài)代理,需要實(shí)現(xiàn)接口的類(lèi)。

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

CGLIB實(shí)現(xiàn)動(dòng)態(tài)代理,并不要求被代理類(lèi)必須實(shí)現(xiàn)接口,底層采用asm字節(jié)碼生成框架生成代理類(lèi)字節(jié)碼(該代理類(lèi)繼承了被代理類(lèi))。

所以被代理類(lèi)一定不能定義為final class并且對(duì)于final 方法不能被代理。

實(shí)現(xiàn)需要

//MethodInterceptor接口的intercept方法
/**
*obj 代理對(duì)象
*method 委托類(lèi)方法,被代理對(duì)象的方法字節(jié)碼對(duì)象
*arg 方法參數(shù)
*MethodProxy 代理方法MethodProxy對(duì)象,每個(gè)方法都會(huì)對(duì)應(yīng)有這樣一個(gè)對(duì)象 
*/
public Object intercept(Object obj, Method method, Object[] arg, MethodProxy proxy)
Ehancer enhancer = new Enhancer() //Enhancer為字節(jié)碼增強(qiáng)器,很方便對(duì)類(lèi)進(jìn)行擴(kuò)展
enhancer.setSuperClass(被代理類(lèi).class);
enhancer.setCallback(實(shí)現(xiàn)MethodInterceptor接口的對(duì)象)
enhancer.create()//返回代理對(duì)象,是被代理類(lèi)的子類(lèi)

代碼實(shí)現(xiàn)

UserDaoImpl 用戶(hù)實(shí)現(xiàn)類(lèi)(RealSubject)

public class UserDaoImpl {
    public boolean insert(String name) {
        System.out.println("insert name=" + name);
        return true;
    }
    public final boolean insert1(String name) {
        System.out.println("final insert name=" + name);
        return true;
    }
}

CglibProxy CGLIB代理類(lèi)(Proxy)

public class CglibProxy implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("----------before----------");
        System.out.println("Proxy=" + o.getClass());
        System.out.println("method=" + method);
        System.out.println("args=" + Arrays.toString(objects));
        System.out.println("methodProxy=" + methodProxy);
        //執(zhí)行目標(biāo)方法對(duì)象
        Object result = methodProxy.invokeSuper(o, objects);
        System.out.println("----------after----------");
        return result;
    }
}

ProxyFactory 代理工廠(chǎng)

public class ProxyFactory {
    private static Enhancer enhancer = new Enhancer();
    private static CglibProxy cglibProxy = new CglibProxy();
    public static Object getProxy(Class cls) {
        enhancer.setSuperclass(cls);
        enhancer.setCallback(cglibProxy);
        return enhancer.create();
    }
    public static void main(String[] args) {
        UserDaoImpl userDao = (UserDaoImpl) getProxy(UserDaoImpl.class);
        userDao.insert("zc");
    }
}

5

思考

為什么這里面使用 invokeSuper() ,不使用 invoke()

1.Method method 是被代理對(duì)象的方法字節(jié)碼對(duì)象。

2.MethodProxy methodProxy 是代理對(duì)象的方法字節(jié)碼對(duì)象。

使用 MethodProxy 的好處:

不需要給代理對(duì)象傳入被代理對(duì)象,效率更高。不會(huì)出現(xiàn)死循環(huán)的問(wèn)題。

第一點(diǎn)查看代碼就可以看出,對(duì)第二點(diǎn)進(jìn)行講解:

如何出現(xiàn)死循環(huán)的現(xiàn)象:

	Proxy.newProxyInstance(xxx, xxx,
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    	...
                      //加入這一句  
                    	proxy.toString();
                    	...
                    }
                });

原因:代理對(duì)象方法的時(shí)候,都會(huì)經(jīng)過(guò)攔截器方法。因此,如果在攔截器中再調(diào)用代理對(duì)象的方法,就會(huì)再次進(jìn)入攔截器,這樣就形成了死循環(huán)。

**invokeSuper()**方法,可以使用代理對(duì)象父類(lèi)的方法(就是被代理對(duì)象)而不必經(jīng)過(guò)攔截器-----詳情可以學(xué)習(xí):《類(lèi)加載機(jī)制》、《雙親委派模型》

總結(jié)

本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • Spring Validation方法實(shí)現(xiàn)原理分析

    Spring Validation方法實(shí)現(xiàn)原理分析

    這篇文章主要介紹了Spring Validation實(shí)現(xiàn)原理分析,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-07-07
  • Java設(shè)計(jì)通用的返回?cái)?shù)據(jù)格式過(guò)程講解

    Java設(shè)計(jì)通用的返回?cái)?shù)據(jù)格式過(guò)程講解

    現(xiàn)在很多的項(xiàng)目server端返回client端的數(shù)據(jù)多數(shù)以JSON格式返回,同時(shí)結(jié)合其它需要,通常加一下?tīng)顟B(tài)碼和信息之類(lèi),給前端處理帶來(lái)很大的方便,這篇文章就用Java設(shè)計(jì)了通用的返回?cái)?shù)據(jù)格式,感興趣的同學(xué)可以參考下文
    2023-05-05
  • Java自定義注解實(shí)現(xiàn)Redis自動(dòng)緩存的方法

    Java自定義注解實(shí)現(xiàn)Redis自動(dòng)緩存的方法

    本篇文章主要介紹了Java自定義注解實(shí)現(xiàn)Redis自動(dòng)緩存的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-04-04
  • java使用nio2拷貝文件的示例

    java使用nio2拷貝文件的示例

    這篇文章主要介紹了java使用nio2拷貝文件的示例,需要的朋友可以參考下
    2014-04-04
  • JavaEE的進(jìn)程,線(xiàn)程和創(chuàng)建線(xiàn)程的5種方式詳解

    JavaEE的進(jìn)程,線(xiàn)程和創(chuàng)建線(xiàn)程的5種方式詳解

    這篇文章主要為大家詳細(xì)介紹了JavaEE的進(jìn)程,線(xiàn)程和創(chuàng)建線(xiàn)程的5種方式,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-03-03
  • MyBatis-Plus自定義SQL和復(fù)雜查詢(xún)的實(shí)現(xiàn)

    MyBatis-Plus自定義SQL和復(fù)雜查詢(xún)的實(shí)現(xiàn)

    MyBatis-Plus增強(qiáng)了MyBatis的功能,提供注解和XML兩種自定義SQL方式,支持復(fù)雜查詢(xún)?nèi)缍啾黻P(guān)聯(lián)、動(dòng)態(tài)分頁(yè)等,通過(guò)注解如@Select、@Insert、@Update、@Delete實(shí)現(xiàn)CRUD操作,本文就來(lái)介紹一下,感興趣的可以了解一下
    2024-10-10
  • java更改圖片大小示例分享

    java更改圖片大小示例分享

    這篇文章主要介紹了java更改圖片大小示例,方法中指定路徑 ,舊文件名稱(chēng) ,新文件名稱(chēng),n 改變倍數(shù)就可以完成更改圖片大小,需要的朋友可以參考下
    2014-03-03
  • java學(xué)生信息管理系統(tǒng)源代碼

    java學(xué)生信息管理系統(tǒng)源代碼

    這篇文章主要為大家詳細(xì)介紹了java學(xué)生信息管理系統(tǒng)源代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • SpringBoot+easypoi實(shí)現(xiàn)數(shù)據(jù)的Excel導(dǎo)出

    SpringBoot+easypoi實(shí)現(xiàn)數(shù)據(jù)的Excel導(dǎo)出

    這篇文章主要為大家詳細(xì)介紹了SpringBoot+easypoi實(shí)現(xiàn)數(shù)據(jù)的Excel導(dǎo)出,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-05-05
  • Java的字符串中對(duì)子字符串的查找方法總結(jié)

    Java的字符串中對(duì)子字符串的查找方法總結(jié)

    這篇文章主要介紹了Java的字符串中對(duì)子字符串的查找方法總結(jié),是Java入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-11-11

最新評(píng)論