深挖JDK動態代理(一)

lonecloud發表於2018-06-09

 最近在研究RPC框架,避免不了的就是在RPC呼叫中使用最多的則是動態代理的機制了,基於此,我們先來研究一下JDK動態代理

我們先來嘗試著編寫一下JDK動態代理的程式碼

1. 由於JDK動態代理是基於介面的,所以不免需要先編寫一個介面,並宣告一個getHello方法

package cn.lonecloud.study.service;

import cn.lonecloud.study.dto.HelloDto;

/**
 * @author lonecloud
 * @version v1.0
 * @Package cn.lonecloud.study
 * @Description: TODO
 * @date 2018/6/8下午4:36
 */
public interface HelloService {

    HelloDto getHello(String name);
}

2. 有了介面,肯定是需要實現類,並將getHello方法給予實現

package cn.lonecloud.study;

import cn.lonecloud.study.dto.HelloDto;
import cn.lonecloud.study.service.HelloService;

/**
 * @author lonecloud
 * @version v1.0
 * @Package cn.lonecloud.study
 * @Description: TODO
 * @date 2018/6/8下午11:35
 */
public class HelloImpl implements HelloService {
    @Override
    public HelloDto getHello(String name) {
        return new HelloDto();
    }
}  

這兩個硬性條件有了,則我們來編寫動態代理類了

1. 首先我們先來了解兩個API:

  1. public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h):該類用於建立動態代理類的例項,

    1. loader:類的類載入器:一般使用者類為AppClassLoader,可通過類名.class.getClassLoader()獲得

    2. interfaces:介面陣列,前面我們說過,jdk動態代理是基於介面來實現的,所以這個引數就是用來傳遞介面陣列啦

    3. h:用於具體實現Handler,也就是這裡執行相關的主要業務邏輯的地方了

  2. InvocationHandler:該介面用於實現動態代理類的相關業務邏輯

    1. 通常需要使用動態代理的話必須實現該介面,並重寫其裡面的invoke方法。

    2. invoke(Object proxy, Method method, Object[] args)throws Throwable; 

      1. proxy:代理類物件

      2. method:執行的方法

      3. args:相關的引數

編寫相關的代理類

package cn.lonecloud.study;

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

/**
 * @author lonecloud
 * @version v1.0
 * @Package cn.lonecloud.study
 * @Description: TODO
 * @date 2018/6/8下午11:23
 */
public class ProxyDemo {
    //定義實現類物件
    Object target;
    //建構函式
    public ProxyDemo(Object target) {
        this.target = target;
    }
    //獲取實現類方法
    @SuppressWarnings("unchecked")
    public <T> T getProxy(Class<T> clazz){
       //獲取代理例項
        return(T) Proxy.newProxyInstance(clazz.getClassLoader(),new Class[]{clazz}, (proxy, method, args) -> {
            System.out.println(method.getName());
            //執行代理物件
            return method.invoke(target,args);
        });
    }
}

  clazz.getClassLoader()獲取的是類載入器,第二個引數建立了一個Class[]陣列物件,由於傳遞過來的clazz為介面,所以可以這樣寫

執行:

        HelloService proxy1 = new ProxyDemo(new HelloImpl()).getProxy(HelloService.class);
        HelloDto demo = proxy1.getHello("demo");

  該JDK動態代理的實現基本上就完成了,下一篇文章我們來看一下,jdk動態代理生產的位元組碼檔案究竟是什麼個樣子

深挖JDK動態代理(二):JDK動態生成後的位元組碼分析

相關文章