Java 動態代理 兩種實現方法


        AOP的攔截功能是由java中的動態代理來實現的。說白了,就是在目標類的基礎上增加切面邏輯,生成增強的目標類(該切面邏輯或者在目標類函數執行之前,或者目標類函數執行之后,或者在目標類函數拋出異常時候執行。不同的切入時機對應不同的Interceptor的種類,如BeforeAdviseInterceptor,AfterAdviseInterceptor以及ThrowsAdviseInterceptor等)。那么動態代理是如何實現將切面邏輯(advise)織入到目標類方法中去的呢?下面我們就來詳細介紹並實現AOP中用到的兩種動態代理。AOP的源碼中用到了兩種動態代理來實現攔截切入功能:jdk動態代理和cglib動態代理。兩種方法同時存在,各有優劣。jdk動態代理是由java內部的反射機制來實現的,cglib動態代理底層則是借助asm來實現的。總的來說,反射機制在生成類的過程中比較高效,而asm在生成類之后的相關執行過程中比較高效(可以通過將asm生成的類進行緩存,這樣解決asm生成類過程低效問題)。還有一點必須注意:jdk動態代理的應用前提,必須是目標類基於統一的接口。如果沒有上述前提,jdk動態代理不能應用。由此可以看出,jdk動態代理有一定的局限性,cglib這種第三方類庫實現的動態代理應用更加廣泛,且在效率上更有優勢。

        1.定義接口和實現接口

package com.xiaoqiang.design;

public interface Person {

      public void buy();

    public void buy1();
}
package com.xiaoqiang.design;

public class xiaoQiang implements  Person {
    private String name;
    private String house;

    public xiaoQiang(String name, String house) {
        this.name = name;
        this.house = house;
    }

    @Override
    public void buy() {
        System.out.println(name+"買了"+house);
    }

    @Override
    public void buy1() {
        System.out.println("我是你爸爸");
    }
}

         2.jdk動態代理的實現

jdk動態代理是jdk原生就支持的一種代理方式,它的實現原理,就是通過讓target類和代理類實現同一接口,代理類持有target對象,來達到方法攔截的作用,這樣通過接口的方式有兩個弊端,一個是必須保證target類有接口,第二個是如果想要對target類的方法進行代理攔截,那么就要保證這些方法都要在接口中聲明,實現上略微有點限制。

package com.xiaoqiang.design;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxySaler implements InvocationHandler {

    public Person person;

    public Object newInstall(Person person)
    {
        this.person=person;
        return  Proxy.newProxyInstance(person.getClass().getClassLoader(),person.getClass().getInterfaces(),this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("執行方法前的操作");
        if(method.getName().equals("buy")) {
            person.buy();
        }
        if(method.getName().equals("buy1"))
        {
            person.buy1();
        }
        System.out.println("執行方法后的操作");
        return null;
    }
}

           3.運行類

package com.xiaoqiang.design;

import sun.misc.ProxyGenerator;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class TestMain {

    public static void main(String[] args) {
        ProxySaler proxySaler=new ProxySaler();
        Person object= (Person) proxySaler.newInstall(new xiaoQiang("黃豪強","南山區"));
        object.buy1();
        object.buy();




       /* byte[] bytes=ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{object.getClass()});
        try {
            OutputStream outputStream=new FileOutputStream("$abc.txt");
            outputStream.write(bytes);
            outputStream.flush();
            outputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }*/
        /* System.out.println(aa);*/
      /*try{
          System.out.println(object.getClass().getMethod("buy",Person.class));
      }
      catch (Exception e)
      {
          System.out.println("異常");
      }*/
    /*    object.buy1();*/
    }
}

        Cglib方法的動態代理:

        需要導入Cglib的jar包:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.xiaoqiang</groupId>
    <artifactId>cglibproxy</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/cglib/cglib -->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.2.12</version>
        </dependency>

    </dependencies>

</project>

 

        1.定義被代理的方法:

/**
 * @author 黃豪強
 * @create 2019/7/24 8:51
 */
public class PlayGame {

    public void play()
    {
        System.out.println("打籃球很厲害");
    }
}

         2.代理類

import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @author 黃豪強
 * @create 2019/7/24 8:51
 */
public class CglibProxy implements MethodInterceptor {

    public Object newInstall(Object object) {

        return Enhancer.create(object.getClass(), this);
    }


    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("先熱身一會");
        methodProxy.invokeSuper(o,objects);
        System.out.println("打完了");
        return null;
    }


}

          3.運行類

/**
 * @author 黃豪強
 * @create 2019/7/24 9:09
 */
public class ProxyTeest {
    public static void main(String[] args) {
           CglibProxy cglibProxy=new CglibProxy();
            PlayGame playGame= (PlayGame) cglibProxy.newInstall(new PlayGame());
            playGame.play();
    }
}

          4.運行結果

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM