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

JDK動態(tài)代理,代理接口沒有實現(xiàn)類,實現(xiàn)動態(tài)代理方式

 更新時間:2021年08月24日 09:06:27   作者:DayFight_DayUp  
這篇文章主要介紹了JDK動態(tài)代理,代理接口沒有實現(xiàn)類,實現(xiàn)動態(tài)代理方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

JDK動態(tài)代理,代理接口沒有實現(xiàn)類,實現(xiàn)動態(tài)代理

JDK代理,代理的是接口,那么筆者想一想,既然代理的是接口,那如果沒有實現(xiàn)類怎么辦,能不能代理。答案是可以的,Mybatis就是這樣的。

Mybatis使用JDK動態(tài)代理來實現(xiàn)Mapper接口,事先保存好Mapper接口,和接口聲明的方法,返回值,參數(shù)類型,然后代理類的方法調(diào)用的時候使用MapperMethod這個事先放入方法緩存里的對象來真實調(diào)用功能。

筆者極度簡化了一下代碼:

被代理的接口:

public interface Subject2 { 
    String selectById();
}

這個接口可以看成是Mapper接口

代理對象:

public class SubjectProxy2<T> implements InvocationHandler { 
    private Class<T> proxyInterface;
    //這里可以維護一個緩存,存這個接口的方法抽象的對象     
    SubjectProxy2(Class<T> proxyInterface){
        this.proxyInterface = proxyInterface;
    } 
 
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().equals("selectById")){
            //String result = (String) method.invoke(proxyInterface,args);
            //這里可以得到方法抽象對象來調(diào)用真的的查詢方法
            System.out.println("selectById調(diào)用成功");
        }
        return null;
    } 
    public T getProxy(){
        return (T) Proxy.newProxyInstance(proxyInterface.getClassLoader(),new Class[]{proxyInterface},this);
    }
}

這個代理類使用了泛型,說明這個代理類可以代理所有的mapper接口。

那么接下來測試一下:

public class ProxyTest2 { 
    public static void main(String[] args) {
        SubjectProxy2<Subject2> subjectProxy2 = new SubjectProxy2(Subject2.class);
        Subject2 subject2 = subjectProxy2.getProxy();
        subject2.selectById();
    }
}

結(jié)果不言而喻。肯定會有相應的輸出

沒有看mybatis源碼的時候,我以為動態(tài)代理一定要要有實現(xiàn)類才能代理,但是看了優(yōu)秀的頂級大牛的源碼之后,我才發(fā)現(xiàn),原來還可以這樣。

jdk動態(tài)代理為什么要接口

jdk的動態(tài)代理為什么用接口,內(nèi)部是什么原理呢?看了幾篇文章貌似都沒講的清楚明白,因此來解釋一下。

先通過一個簡單例子實現(xiàn)功能:

//接口
public interface SayService { 
 void say(String name);
}
//實現(xiàn)類
public class SayServiceImpl implements SayService{ 
 @Override
 public void say(String name) {
  System.out.println(name);
 }
}

然后再自定義一個增強類, 實現(xiàn)InvocationHandler接口:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; 
public class WavingInvocationHandler  implements InvocationHandler{ 
 private Object target; 
 public void setTarget(Object target) {
  this.target = target;
 }
 
 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  System.out.println("方法執(zhí)行之前!");
  Object obj = method.invoke(target, args);
  System.out.println("方法執(zhí)行之后!");
  return obj;
 }
}

編寫測試方法:

import sun.misc.ProxyGenerator; 
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Proxy;
 
public class Test { 
 public static void main(String[] args) { 
  //接口
  SayService sayService = new SayServiceImpl();
  //織入類
  WavingInvocationHandler handler = new WavingInvocationHandler();
  handler.setTarget(sayService);
  //代理類--增強的對象
  SayService s = (SayService) Proxy.newProxyInstance(
    sayService.getClass().getClassLoader(),
    sayService.getClass().getInterfaces(), handler);
 
  s.say("say()");//執(zhí)行代理對象完成業(yè)務
  /**
   方法執(zhí)行之前!
   say()
   方法執(zhí)行之后!
   */
 
  //將jdk中生成代理類輸出到本地.Class文件,之后可以通過反編譯軟件打開查看
  createProxyClassFile("test12345",sayService.getClass().getInterfaces()); 
 }
 
 private static void createProxyClassFile(String name,Class<?> [] interfaces){
  byte[] data = ProxyGenerator.generateProxyClass(name,interfaces);//該方法為jdk中生成代理類的核心方法
  FileOutputStream out =null;
  try {
   out = new FileOutputStream(name+".class");
   System.out.println((new File(name)).getAbsolutePath());
   out.write(data);
  } catch (FileNotFoundException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  }finally {
   if(null!=out) try {
    out.close();
   } catch (IOException e) {
    e.printStackTrace();
   }
  }
 } 
}

好奇心強的小伙伴一定看過newProxyInstance方法看過了,

里面的getProxyClass方法創(chuàng)建代理類:

/*
 * Look up or generate the designated proxy class.
 */
Class<?> cl = getProxyClass0(loader, intfs);

具體是里面的哪個方法生成的,小伙伴們不用找半天了,慢慢debug后會發(fā)現(xiàn),就是上面提到的

ProxyGenerator.generateProxyClass()

通過該方法生成的代理類如下:

通過反編譯查看源碼,一看便知接口的作用

JDK的動態(tài)代理是靠多態(tài)和反射來實現(xiàn)的,它生成的代理類需要實現(xiàn)你傳入的接口,并通過反射來得到接口的方法對象(下文中的m3),并將此方法對象傳參給增強類(上文中的WavingInvocationHandler類)的invoke方法去執(zhí)行,從而實現(xiàn)了代理功能,故接口是jdk動態(tài)代理的核心實現(xiàn)方式,沒有它就無法通過反射找到方法,所以這也是必須有接口的原因。不知道大家明白否

public final class test12345 extends Proxy implements SayService {
    //1、該類實現(xiàn)你傳入的接口并實現(xiàn)方法 
    // 2、通過構(gòu)造方法傳入你定義的增強類對象 
    // 3、通過反射該接口,得到接口里的Method對象并傳參給增強類,然后執(zhí)行Invoke實現(xiàn)功能
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;
 
    public test12345(InvocationHandler paramInvocationHandler) {
        super(paramInvocationHandler);//2.此處的super指向Proxy中的構(gòu)造方法并賦值(下文的h就是此處的增強類對象),
    }
 
    //略去無關的hashcode和equals方法
    public final void say(String paramString) {
        try {
            this.h.invoke(this, m3, new Object[]{paramString});//3.此處的h就是InvocationHandler對象,invoke就是你增強類里的方法,傳入接口的方法和參數(shù)并執(zhí)行你增強類里的invoke方法,即完成了整個操作!
        } catch (Error | RuntimeException localError) {
            throw localError;
        } catch (Throwable localThrowable) {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }
 
    static {//1.靜態(tài)代碼塊給屬性賦值,初始化接口中的方法對象(主要是下面的m3)
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m3 = Class.forName("com.chenrui.core.jdk.SayService").getMethod("say", new Class[]{Class.forName("java.lang.String")});
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
        } catch (NoSuchMethodException localNoSuchMethodException) {
            throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
        } catch (ClassNotFoundException localClassNotFoundException) {
            throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
        }
    }
}

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • 使用eclipse創(chuàng)建java項目的方法

    使用eclipse創(chuàng)建java項目的方法

    這篇文章主要為大家詳細介紹了使用eclipse創(chuàng)建java項目的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-04-04
  • Spring bean對象實例化實現(xiàn)過程圖解

    Spring bean對象實例化實現(xiàn)過程圖解

    這篇文章主要介紹了Spring bean對象實例化實現(xiàn)過程圖解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-07-07
  • Java如何基于wsimport調(diào)用wcf接口

    Java如何基于wsimport調(diào)用wcf接口

    這篇文章主要介紹了Java如何基于wsimport調(diào)用wcf接口,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-06-06
  • Spring?Cloud?Gateway服務網(wǎng)關限流問題及解決

    Spring?Cloud?Gateway服務網(wǎng)關限流問題及解決

    這篇文章主要介紹了Spring?Cloud?Gateway服務網(wǎng)關限流問題及解決,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • spring mvc中的@ModelAttribute注解示例介紹

    spring mvc中的@ModelAttribute注解示例介紹

    在Spring mvc中,注解@ModelAttribute是一個非常常用的注解,下面這篇文章主要給大家介紹了關于spring mvc中@ModelAttribute注解的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下。
    2017-09-09
  • MyBatis批量添加、修改和刪除

    MyBatis批量添加、修改和刪除

    本文給大家分享mybatis批量添加,修改,刪除的實例代碼,本文代碼簡單易懂,對mybatis 批量添加、修改及刪除相關知識感興趣的朋友一起學習吧
    2016-01-01
  • Java中Elasticsearch的核心概念詳解

    Java中Elasticsearch的核心概念詳解

    這篇文章主要介紹了Java中Elasticsearch的核心概念詳解,Elasticsearch 是一個分布式、免費和開放的搜索和分析引擎,適用于所有類型的數(shù)據(jù),包括文本、數(shù)字、地理空間、結(jié)構(gòu)化和非結(jié)構(gòu)化數(shù)據(jù),需要的朋友可以參考下
    2023-07-07
  • spring中的特殊注解@RequiredArgsConstructor詳解

    spring中的特殊注解@RequiredArgsConstructor詳解

    這篇文章主要介紹了spring中的特殊注解@RequiredArgsConstructor,包括注解注入,構(gòu)造器注入及setter注入,結(jié)合示例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2022-04-04
  • Java編程實現(xiàn)深度優(yōu)先遍歷與連通分量代碼示例

    Java編程實現(xiàn)深度優(yōu)先遍歷與連通分量代碼示例

    這篇文章主要介紹了Java編程實現(xiàn)深度優(yōu)先遍歷與連通分量代碼示例,
    2017-11-11
  • java中out.print和out.write的方法

    java中out.print和out.write的方法

    本文用一個小例子說明java out.print和out.write的方法,大家參考使用吧
    2013-11-11

最新評論

江华| 乌拉特中旗| 泗阳县| 富平县| 合阳县| 奎屯市| 太保市| 宜春市| 古田县| 溧阳市| 苍梧县| 鲜城| 乐亭县| 铁岭市| 平潭县| 林西县| 莎车县| 新绛县| 哈尔滨市| 新化县| 芦溪县| 南皮县| 景东| 左权县| 遂宁市| 临武县| 五常市| 江西省| 保定市| 玛多县| 延安市| 新丰县| 永安市| 姜堰市| 汝城县| 保定市| 营山县| 论坛| 长顺县| 金湖县| 咸宁市|