最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

代理

其他對象提供一種代理以控制這個對象的訪問,在某些情況下一個對象不能直接訪問那個對象時,代理就起到了客戶端和被代理對象 (委托類) 中介作用。

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

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

動態(tài):在程序運行時運用反射機制動態(tài)創(chuàng)建而成。

靜態(tài)代理

1

Subject: 代理類和被代理類實現(xiàn)同樣的接口

Proxy:代理類,里面有被代理類,具體邏輯委托被代理類進行處理

RealSubject:被代理類,可以在其內做一些訪問權限控制,額外的業(yè)務處理

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

代碼實現(xiàn)

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

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

UserDAOImpl 被代理類(RealSubject)

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

ProxyByInterface 代理類,通過實現(xiàn)接口方式實現(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 代理類,通過繼承被代理類實現(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);
    }
}

獲取代理對象客戶端(Client)

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

2

好處:

可以不用動原來類的邏輯,再次增加一些功能,符合開閉原則。

真正的業(yè)務還是交給被代理對象處理的,無須修改原來的類就可以使用代理進行實現(xiàn)。

缺點:

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

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

動態(tài)代理

JDK動態(tài)代理

Jdk動態(tài)代理,針對的是實現(xiàn)接口的類

要求目標對象必須實現(xiàn)接口,因為它創(chuàng)建代理對象的時候是根據(jù)接口創(chuàng)建的。被代理對象可以可以實現(xiàn)多個接口,創(chuàng)建代理時指定創(chuàng)建某個接口的代理對象就可以調用該接口定義的方法了。

需要java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy 類的支持

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

代碼實現(xiàn)

NameDao 姓名-接口(Subject)

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

AgeDao 年齡-接口(Subject)

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

NameAndAgeDaoImpl 姓名、年齡實現(xiàn)類(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,對接口提供的方法進行增強(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í)行目標方法對象
        Object result = method.invoke(target, args);
        System.out.println("----------after----------");
        return result;
    }
}

ProxyFactory 代理工廠

public class ProxyFactory {
    public static Object getProxy(Object proxyObj) {
        /**
         * loader 指定加載jvm運行時動態(tài)生成的代理對象的加載器
         * interface 真實對象實現(xiàn)的所有接口
         * h 實現(xiàn)InvocationHandler接口對象
         */
      // 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

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

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

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 類:

4

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

CGLib動態(tài)代理

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

所以被代理類一定不能定義為final class并且對于final 方法不能被代理。

實現(xiàn)需要

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

代碼實現(xiàn)

UserDaoImpl 用戶實現(xiàn)類(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代理類(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í)行目標方法對象
        Object result = methodProxy.invokeSuper(o, objects);
        System.out.println("----------after----------");
        return result;
    }
}

ProxyFactory 代理工廠

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 是被代理對象的方法字節(jié)碼對象。

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

使用 MethodProxy 的好處:

不需要給代理對象傳入被代理對象,效率更高。不會出現(xiàn)死循環(huá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();
                    	...
                    }
                });

原因:代理對象方法的時候,都會經過攔截器方法。因此,如果在攔截器中再調用代理對象的方法,就會再次進入攔截器,這樣就形成了死循環(huán)。

**invokeSuper()**方法,可以使用代理對象父類的方法(就是被代理對象)而不必經過攔截器-----詳情可以學習:《類加載機制》、《雙親委派模型》

總結

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關注腳本之家的更多內容!

相關文章

  • Spring?@Cacheable讀取配置常量方式

    Spring?@Cacheable讀取配置常量方式

    這篇文章主要介紹了Spring?@Cacheable讀取配置常量方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • 學java得這樣學,學習確實也得這樣

    學java得這樣學,學習確實也得這樣

    學java得這樣學,學習東西確實也得這樣
    2008-02-02
  • Java多線程wait()和notify()方法詳細圖解

    Java多線程wait()和notify()方法詳細圖解

    wait()和notify()是直接隸屬于Object類,也就是說所有對象都擁有這一對方法,下面這篇文章主要給大家介紹了關于Java多線程wait()和notify()方法詳細圖解的相關資料,需要的朋友可以參考下
    2022-10-10
  • MyBatis核心源碼深度剖析SQL語句執(zhí)行過程

    MyBatis核心源碼深度剖析SQL語句執(zhí)行過程

    這篇文章主要介紹了MyBatis核心源碼深度剖析SQL執(zhí)行過程,mybatis執(zhí)行SQL的流程都是根據(jù)statement字符串從configuration中獲取對應的mappedStatement,本文通過實例代碼給大家介紹的非常詳細,需要的朋友參考下吧
    2022-05-05
  • Java中的SimpleDateFormat的線程安全問題詳解

    Java中的SimpleDateFormat的線程安全問題詳解

    這篇文章主要介紹了Java中的SimpleDateFormat的線程安全問題詳解,sonar 是一個代碼質量管理工具,SonarQube是一個用于代碼質量管理的開放平臺,為項目提供可視化報告, 連續(xù)追蹤項目質量演化過程,需要的朋友可以參考下
    2024-01-01
  • SpringMVC獲取請求參數(shù)筆記整理

    SpringMVC獲取請求參數(shù)筆記整理

    本文記錄和分享在學習Spring MVC過程中的筆記,通過案例示例代碼分析給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-04-04
  • RestTemplate文件上傳下載與大文件流式下載

    RestTemplate文件上傳下載與大文件流式下載

    這篇文章主要為大家介紹了RestTemplate文件上傳下載與大文件流式下載的使用方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助祝大家多多進步
    2022-03-03
  • mybatis 中 foreach collection的用法小結(三種)

    mybatis 中 foreach collection的用法小結(三種)

    這篇文章主要介紹了mybatis 中 foreach collection的用法小結(三種),需要的朋友可以參考下
    2017-10-10
  • SpringBoot利用jackson格式化時間的三種方法

    SpringBoot利用jackson格式化時間的三種方法

    日常開發(fā)過程中經常會使用json進行數(shù)據(jù)的傳輸,這就涉及到了對象和json的相互轉化,常用的解決方案有:Jackson(推薦)、谷歌的Gson、阿里的Fastjson,這篇文章主要給大家介紹了關于SpringBoot如何利用jackson格式化時間的相關資料,需要的朋友可以參考下
    2021-06-06
  • java多線程復制文件的實例代碼

    java多線程復制文件的實例代碼

    java多線程復制文件的實例代碼,需要的朋友可以參考一下
    2013-03-03

最新評論

昌都县| 莱阳市| 汉中市| 合作市| 施甸县| 石嘴山市| 报价| 霸州市| 建始县| 阜宁县| 龙井市| 会昌县| 大田县| 平顺县| 明溪县| 图木舒克市| 武汉市| 和硕县| 板桥市| 盘山县| 宁阳县| 六枝特区| 湘潭县| 遵化市| 台湾省| 且末县| 揭阳市| 大渡口区| 贺兰县| 保靖县| 霞浦县| 潜山县| 广元市| 红原县| 永安市| 武宁县| 广德县| 博兴县| 江门市| 延边| 齐河县|