在线不卡日本ⅴ一区v二区_精品一区二区中文字幕_天堂v在线视频_亚洲五月天婷婷中文网站

  • <menu id="lky3g"></menu>
  • <style id="lky3g"></style>
    <pre id="lky3g"><tt id="lky3g"></tt></pre>

    mybatis : 靜態(tài)代理 + jdk動態(tài)代理

    mybatis : 靜態(tài)代理 + jdk動態(tài)代理

    背景

    • 有時目標對象不可直接訪問,只能通過代理對象訪問
    • 圖示:
    • 示例1:房東 ===> 目標對象房屋中介 ===> 代理對象你,我 ===> 客戶端對象
    • 示例2:運營商(電信,移動,聯(lián)通) ===> 目標對象第三方公司 ===> 代理對象開發(fā)的應(yīng)用程序需要發(fā)送短信的功能(或者需要支付功能) ===> 客戶端對象

    代理模式的作用

    • 控制客戶對目標對象的訪問
    • 增強訪問功能

    代理模式的分類

    靜態(tài)代理

    特點

    • 目標對象和代理對象實現(xiàn)同一個業(yè)務(wù)接口
    • 目標對象必須實現(xiàn)接口
    • 代理對象在程序運行前就已經(jīng)存在

    靜態(tài)代理示例與原理分析

    業(yè)務(wù)背景

    分析

    • 定義業(yè)務(wù)接口:面向接口編程,定義業(yè)務(wù)
    • 目標對象實現(xiàn)接口:業(yè)務(wù)的核心功能到底怎么實現(xiàn)
    • 代理對象(擴展業(yè)務(wù) + 核心業(yè)務(wù))實現(xiàn)了目標對象所實現(xiàn)的接口,說明代理對象有資歷進行代理對核心業(yè)務(wù)進行擴展調(diào)用目標對象實現(xiàn)核心業(yè)務(wù)(只能目標對象自己完成)
    • 客戶:無法直接訪問目標對象,要訪問代理對象

    代碼實現(xiàn)

    • 面向接口編程
      • 成員變量是接口類型
      • 傳入目標對象,方法參數(shù)設(shè)計為接口
      • 調(diào)用時,接口指向?qū)崿F(xiàn)類
    • 靜態(tài)代理對象代碼
    • package com.example.service.impl; import com.example.service.Service; public class Agent implements Service { //定義接口對象 public Service target; public Agent(){} //傳入接口對象 public Agent(Service target){ this.target = target; } @Override public void sing() { System.out.println(“協(xié)商演出時間……”); System.out.println(“協(xié)商演出地點……”); //目標對象完成核心業(yè)務(wù),接口指向?qū)崿F(xiàn)類,調(diào)用實現(xiàn)類的方法 target.sing(); System.out.println(“協(xié)商演出費用……”); } }

    靜態(tài)代理優(yōu)缺點

    • 優(yōu)點:能夠靈活地進行目標對象的切換適用于業(yè)務(wù)固定,目標對象可靈活切換的場景
    • 缺點:無法進行功能的靈活處理,當(dāng)業(yè)務(wù)發(fā)生改變時,所有涉及到的實現(xiàn)類代碼和代理對象代碼都要改變

    動態(tài)代理

    JDK動態(tài)代理

    特點

    • 目標對象必須實現(xiàn)業(yè)務(wù)接口
    • JDK代理對象不需要實現(xiàn)業(yè)務(wù)接口
    • JDK代理對象在程序運行前不存在,程序運行時動態(tài)的在內(nèi)存中構(gòu)建(根據(jù)受代理的對象動態(tài)創(chuàng)建)
    • JDK動態(tài)代理可以靈活的進行業(yè)務(wù)功能的切換

    JDK動態(tài)代理用到的類和接口

    • 使用現(xiàn)有的工具類完成JDK動態(tài)代理
    • 先了解兩個單詞的意思InvocationHandler:調(diào)用處理程序invoke:調(diào)用

    Method類

    • 反射時用的類,用來進行目標對象的目標方法的反射調(diào)用
    • method對象,接住我們正在調(diào)用的方法 sing(),show()method == sing(),show(),即:待調(diào)用的方法method.invoke() ==> 相當(dāng)于手工調(diào)用目標方法 sing(),show();

    InvocationHandler接口

    • 用來實現(xiàn)代理和業(yè)務(wù)功能,我們在調(diào)用時使用匿名內(nèi)部實現(xiàn)匿名內(nèi)部實現(xiàn):new接口的同時,重寫接口中的方法(相當(dāng)于定義了該接口的一個實現(xiàn)類)

    Proxy類

    • 位于:java.lang.reflect.Proxy包下
    • 有一個核心方法:Proxy.newProxyInstance(….),專門獲取動態(tài)代理對象,有三個參數(shù)
      • 參數(shù)1:ClassLoader loader
        • 目標對象的類加載器
        • 目的:獲取類方法等信息,畢竟底層還是要調(diào)用受代理對象所實現(xiàn)的方法
        • 傳入:targetObj.getClass().getClassLoader();
      • 參數(shù)2:Class[] interfaces
        • 目標對象實現(xiàn)的所有接口,類的接口可以有多個
        • 目的:獲取目標對象實現(xiàn)的所有接口以及接口的相關(guān)信息,畢竟底層要知道目標對象都可以完成哪些業(yè)務(wù)操作
        • 傳入:targetObj.getClass().getInterfaces();
      • 上面兩個參數(shù)為代理對象動態(tài)的創(chuàng)建和調(diào)用目標對象的方法提供了數(shù)據(jù)支持,第3個參數(shù)相當(dāng)于調(diào)用程序
      • 參數(shù)3:InvocationHandler
        • 實現(xiàn)代理功能的接口,這里代理功能包括:擴展的功能 + 核心業(yè)務(wù)功能,傳入的匿名內(nèi)部實現(xiàn)如下
      • new InvocationHandler() { @Override public Object invoke( Object obj, //用來反射調(diào)用方法 Method method, //待調(diào)用方法需要的參數(shù) Object[] args) throws Throwable { //擴展業(yè)務(wù) System.out.println(“協(xié)商演出時間……”); System.out.println(“協(xié)商演出地點……”); //核心業(yè)務(wù),具體調(diào)用什么方法根據(jù)外層業(yè)務(wù)來反射調(diào)用對應(yīng)方法 Object res = method.invoke(target, args); //擴展業(yè)務(wù) System.out.println(“協(xié)商演出費用……”); //目標對象執(zhí)行的目標方法的返回值 return res; } }

    JDK動態(tài)代理示例

    • 代理工廠代碼
    • package com.example.proxy; import com.example.service.Service; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyFactory { //目標對象 Service target; public ProxyFactory(){} public ProxyFactory(Service target){ this.target = target; } //返回代理對象 public Object getAgent(){ return Proxy.newProxyInstance( //需要知道受代理對象的類信息 target.getClass().getClassLoader(), //需要知道受代理對象實現(xiàn)的所有接口信息 target.getClass().getInterfaces(), //反射調(diào)用目標對象的目標方法 new InvocationHandler() { @Override public Object invoke( Object obj, //用來反射調(diào)用方法 Method method, //待調(diào)用方法需要的參數(shù) Object[] args) throws Throwable { //擴展業(yè)務(wù) System.out.println(“協(xié)商演出時間……”); System.out.println(“協(xié)商演出地點……”); //核心業(yè)務(wù),具體調(diào)用什么方法根據(jù)外層業(yè)務(wù)來反射調(diào)用對應(yīng)方法 Object res = method.invoke(target, args); //擴展業(yè)務(wù) System.out.println(“協(xié)商演出費用……”); //目標對象執(zhí)行的目標方法的返回值 return res; } } ); } }
    • 測試代碼示例
    • package com.example.proxy; import com.example.service.Service; import com.example.service.impl.SuperStarZhou; import org.junit.Test; public class TestProxyFactory { @Test public void testGetProxy(){ //確定客戶需求 ProxyFactory factory = new ProxyFactory(new SuperStarZhou()); //根據(jù)需求動態(tài)返回對應(yīng)類型的代理對象 Service agent = (Service) factory.getAgent(); //依托對應(yīng)類型的動態(tài)代理對象完成業(yè)務(wù):擴展業(yè)務(wù)(動態(tài)代理對象完成) + 核心業(yè)務(wù)(目標對象完成) agent.sing(); } @Test public void testGetProxy2(){ ProxyFactory factory = new ProxyFactory(new SuperStarZhou()); Service agent = (Service) factory.getAgent(); String res = (String) agent.show(60); System.out.println(res); } }

    注意

    • 可被代理的方法應(yīng)該是受代理對象實現(xiàn)的所有接口中的方法與其所有實體方法的交集
      • 本類中獨有的方法不被代理
    • 類型的轉(zhuǎn)變
    • @Test public void testGetProxy2() { ProxyFactory factory = new ProxyFactory(new SuperStarZhou()); Service agent = (Service) factory.getAgent(); Service liu = new SuperStarLiu(); System.out.println(“類型1: ” + liu.getClass()); System.out.println(“類型2: ” + agent.getClass()); } /* 輸出結(jié)果: 類型1: class com.example.service.impl.SuperStarLiu 類型2: class com.sun.proxy.$Proxy7 */
    鄭重聲明:本文內(nèi)容及圖片均整理自互聯(lián)網(wǎng),不代表本站立場,版權(quán)歸原作者所有,如有侵權(quán)請聯(lián)系管理員(admin#wlmqw.com)刪除。
    上一篇 2022年8月11日 09:25
    下一篇 2022年8月11日 09:25

    相關(guān)推薦

    聯(lián)系我們

    聯(lián)系郵箱:admin#wlmqw.com
    工作時間:周一至周五,10:30-18:30,節(jié)假日休息