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

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

Java設(shè)中動(dòng)態(tài)代理的原理是什么

這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)?lái)有關(guān)Java設(shè)中動(dòng)態(tài)代理的原理是什么,文章內(nèi)容豐富且以專(zhuān)業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

創(chuàng)新互聯(lián)公司是一家以網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)、品牌設(shè)計(jì)、軟件運(yùn)維、成都網(wǎng)站營(yíng)銷(xiāo)、小程序App開(kāi)發(fā)等移動(dòng)開(kāi)發(fā)為一體互聯(lián)網(wǎng)公司。已累計(jì)為集裝箱等眾行業(yè)中小客戶(hù)提供優(yōu)質(zhì)的互聯(lián)網(wǎng)建站和軟件開(kāi)發(fā)服務(wù)。

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

JDK動(dòng)態(tài)代理是java.lang.reflect.*包提供的方式。它必須借助一個(gè)接口才能產(chǎn)生代理對(duì)象,所以先定義接口HelloWorld:

public interface HelloWorld {
  void sayHelloWorld();
}

然后提供實(shí)現(xiàn)類(lèi)HelloWorldImpl來(lái)實(shí)現(xiàn)接口:

public class HelloWorldImpl implements HelloWorld {
  @Override
  public void sayHelloWorld(){
    System.out.println("Hello World");
  }
}

這是最簡(jiǎn)答的Java接口和實(shí)現(xiàn)類(lèi)的關(guān)系,此時(shí)可以開(kāi)始動(dòng)態(tài)代理了。按照我們之前的分析,先要建立代理對(duì)象和真實(shí)對(duì)象的關(guān)系,然后實(shí)現(xiàn)代理邏輯,所以一共分為兩個(gè)步驟。在JDK動(dòng)態(tài)代理中,代理邏輯類(lèi)必須去實(shí)現(xiàn)java.lang.reflect.InvocationHandler接口,它定義了一個(gè)invoke方法,并提供接口數(shù)組用于下掛代理對(duì)象。我們自己定義一個(gè)JDK動(dòng)態(tài)代理的類(lèi):

public class MyJdkProxyExample implements InvocationHandler{
  /**
   * @description 真實(shí)對(duì)象
   **/
  private Object target = null;
  /**
   * @author haozz
   * @date 2018-05-21 10:54
   * @param target 真實(shí)對(duì)象
   * @return 代理對(duì)象
   * @throws
   * @description 建立代理對(duì)象和真實(shí)對(duì)象的代理關(guān)系,并返回代理對(duì)象
   **/
  public Object getProxy(Object target) {
    this.target = target;
    return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
  }
  /**
   * @author haozz
   * @date 2018-05-21 11:09
   * @param proxy 代理對(duì)象
   * @param method 當(dāng)前調(diào)度方法
   * @param args 當(dāng)前方法參數(shù)
   * @return 代理結(jié)果
   * @throws Throwable 異常
   * @description 代理方法邏輯
   **/
  @Override
  public Object invoke(Object proxy, Method method,Object [] args) throws Throwable{
    System.out.println("進(jìn)入代理邏輯方法");
    System.out.println("在調(diào)度真實(shí)對(duì)象之前的服務(wù)");
    Object obj = method.invoke(target,args);//相當(dāng)于調(diào)用sayHelloWorld方法
    System.out.println("在調(diào)度真實(shí)對(duì)象之后的服務(wù)");
    return obj;
  }
}

第一步,通過(guò)getProxy()方法建立代理對(duì)象和真實(shí)對(duì)象的關(guān)系,并返回代理對(duì)象。首先用類(lèi)的屬性target保存了真實(shí)對(duì)象,然后通過(guò)Proxy.newProxyInstance()方法建立并生成代理對(duì)象,該方法中包含3個(gè)參數(shù):

  • 第1個(gè)是類(lèi)加載器,這里采用了target本身的類(lèi)加載器;

  • 第2個(gè)是把生成的動(dòng)態(tài)代理對(duì)象下掛在哪些接口下,這個(gè)寫(xiě)法就是放在target實(shí)現(xiàn)的接口下。HelloWorldImpl對(duì)象的接口顯然就是HelloWorld,代理對(duì)象可以這樣聲明:HelloWorld proxy = xxxx;;

  • 第3個(gè)是定義實(shí)現(xiàn)方法邏輯的代理類(lèi),this表示當(dāng)前對(duì)象,它必須實(shí)現(xiàn)InvocationHandler接口的invoke方法,它就是代理邏輯方法的現(xiàn)實(shí)方法。

第二步,通過(guò)invoke方法實(shí)現(xiàn)代理邏輯方法。invoke方法的3個(gè)參數(shù):

  • proxy,代理對(duì)象,就是getProxy方法生成的對(duì)象;

  • method,當(dāng)前調(diào)度的方法;

  • args,當(dāng)前調(diào)度方法的參數(shù)。

當(dāng)我們使用了代理對(duì)象調(diào)度方法后,它就會(huì)進(jìn)入到invoke方法里面。

Object obj = method.invoke(target,args);

這行代碼相當(dāng)于調(diào)度真實(shí)對(duì)象的方法,只是通過(guò)反射實(shí)現(xiàn)。類(lèi)比前面的例子,proxy相當(dāng)于商務(wù),target相當(dāng)于軟件工程師,getProxy方法就是建立商務(wù)和軟件工程師之間的代理關(guān)系,invoke方法就是商務(wù)邏輯。

測(cè)試JDK動(dòng)態(tài)代理:

  @Test
  public void testJdkProxy(){
    MyJdkProxyExample jdkProxy = new MyJdkProxyExample();
    //綁定關(guān)系,因?yàn)閽煸诮涌贖elloWorld下,所以聲明代理對(duì)象HelloWorld proxy
    HelloWorld proxy = (HelloWorld) jdkProxy.getProxy(new HelloWorldImpl());
    //此時(shí)HelloWorld對(duì)象已經(jīng)是一個(gè)代理對(duì)象,它會(huì)進(jìn)入代理的邏輯方法invoke里
    proxy.sayHelloWorld();
  }

首先通過(guò)getProxy方法綁定了代理關(guān)系,然后在代理對(duì)象調(diào)度sayHelloWorld方法時(shí)進(jìn)入了代理的邏輯,測(cè)試結(jié)果如下:

進(jìn)入代理邏輯方法
在調(diào)度真實(shí)對(duì)象之前的服務(wù)
Hello World
在調(diào)度真實(shí)對(duì)象之后的服務(wù)

此時(shí),在調(diào)度打印Hello World之前和之后都可以加入相關(guān)的邏輯,甚至可以不調(diào)度Hello World的打印。

個(gè)人小結(jié):JDK動(dòng)態(tài)代理要求真實(shí)對(duì)象和代理對(duì)象之間是實(shí)現(xiàn)類(lèi)和接口的關(guān)系,創(chuàng)建一個(gè)代理邏輯類(lèi)實(shí)現(xiàn)InvocationHandler接口,其中g(shù)etProxy方法用于生成代理對(duì)象,然后重寫(xiě)invoke方法。

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

JDK動(dòng)態(tài)代理必須提供接口才能使用,在一些不能提供接口的環(huán)境中,只能采用其他第三方技術(shù),比如CGLIB動(dòng)態(tài)代理,這里提供CGLIB動(dòng)態(tài)代理的相關(guān)jar包,供學(xué)習(xí)和測(cè)試使用。它的優(yōu)勢(shì)在于不需要提供接口,只要一個(gè)非抽象類(lèi)就能實(shí)現(xiàn)動(dòng)態(tài)代理。

CGLIB原理:動(dòng)態(tài)生成一個(gè)要代理類(lèi)的子類(lèi),子類(lèi)重寫(xiě)要代理的類(lèi)的所有不是final的方法。在子類(lèi)中采用方法攔截的技術(shù)攔截所有父類(lèi)方法的調(diào)用,順勢(shì)織入橫切邏輯。它比使用java反射的JDK動(dòng)態(tài)代理要快。CGLIB底層:使用字節(jié)碼處理框架ASM,來(lái)轉(zhuǎn)換字節(jié)碼并生成新的類(lèi)。不鼓勵(lì)直接使用ASM,因?yàn)樗竽惚仨殞?duì)JVM內(nèi)部結(jié)構(gòu)包括class文件的格式和指令集都很熟悉。CGLIB缺點(diǎn):對(duì)于final方法,無(wú)法進(jìn)行代理。CGLIB廣泛地被許多AOP的框架使用,例如Spring AOP和dynaop。Hibernate使用CGLIB來(lái)代理單端single-ended(多對(duì)一和一對(duì)一)關(guān)聯(lián)。

我們以下面這個(gè)類(lèi)為例:

public class ReflectServiceImpl {
  public void sayHello(String name){
    System.out.println("Hello "+name);
  }
}

它不存在實(shí)現(xiàn)任何接口,所以不能使用JDK動(dòng)態(tài)代理,這里采用CGLIB動(dòng)態(tài)代理技術(shù):

public class MyCglibProxyExample implements MethodInterceptor{
  /**
   * @author haozz
   * @date 2018-05-21 15:11
   * @param cls Class類(lèi)
   * @return Class類(lèi)的CGLIB對(duì)象
   * @throws
   * @description 生成CGLIB代理對(duì)象
   **/
  public Object getProxy(Class cls){
    //CGLIB增強(qiáng)類(lèi)對(duì)象
    Enhancer enhancer = new Enhancer();
    //設(shè)置增強(qiáng)類(lèi)型
    enhancer.setSuperclass(cls);
    //定義代理邏輯對(duì)象為當(dāng)前對(duì)象,要求當(dāng)前對(duì)象實(shí)現(xiàn)MethodInterceptor方法
    enhancer.setCallback(this);
    //生成并返回代理對(duì)象
    return enhancer.create();
  }
  /**
   * @author haozz
   * @date 2018-05-21 15:17
   * @param proxy 代理對(duì)象
   * @param method 目標(biāo)方法
   * @param args 目標(biāo)方法參數(shù)
   * @param methodProxy 方法代理
   * @return 代理邏輯返回
   * @throws Throwable 異常
   * @description 代理邏輯方法
   **/
  @Override
  public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)throws Throwable{
    System.out.println("調(diào)用真實(shí)對(duì)象前");
    //CGLIB反射調(diào)用真實(shí)對(duì)象方法
    Object result = methodProxy.invokeSuper(proxy,args);
    System.out.println("調(diào)用真實(shí)對(duì)象后");
    return result;
  }
}

這里用了CGLIB的加強(qiáng)者Enhancer(net.sf.sglib.proxy.Enhancer),通過(guò)設(shè)置超類(lèi)的方法(setSuperclass),然后通過(guò)setCallback方法設(shè)置哪個(gè)類(lèi)為它的代理類(lèi)。其中,參數(shù)this表示當(dāng)前對(duì)象,那就要求用this這個(gè)對(duì)象實(shí)現(xiàn)接口MethodInterceptor(net.sf.sglib.proxy.MethodInterceptor)的方法intercept,然后返回代理對(duì)象。那么此時(shí)當(dāng)前類(lèi)的intercept方法就是其代理邏輯方法,其參數(shù)內(nèi)容見(jiàn)代碼注解,我們?cè)诜瓷湔鎸?shí)對(duì)象方法前后進(jìn)行了打印,CGLIB是通過(guò)如下代碼完成的:

Object result = methodProxy.invokeSuper(proxy,args);

測(cè)試一下CGLIB動(dòng)態(tài)代理:

  @Test
  public void testCglibProxy(){
    MyCglibProxyExample cglibProxy = new MyCglibProxyExample();
    ReflectServiceImpl obj = (ReflectServiceImpl) cglibProxy.getProxy(ReflectServiceImpl.class);
    obj.sayHello("haozz");
  }

得到結(jié)果:

調(diào)用真實(shí)對(duì)象前
Hello haozz
調(diào)用真實(shí)對(duì)象后

上述就是小編為大家分享的Java設(shè)中動(dòng)態(tài)代理的原理是什么了,如果剛好有類(lèi)似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。


文章題目:Java設(shè)中動(dòng)態(tài)代理的原理是什么
URL標(biāo)題:http://weahome.cn/article/pogcgc.html

其他資訊

在線(xiàn)咨詢(xún)

微信咨詢(xún)

電話(huà)咨詢(xún)

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部