天天看點

動态代理實作原理

動态代理由來

Java程式員應該都知道,靜态代理就是使用一個代理類(Proxy)來完成想要完成的事情,Proxy類通過編譯器編譯成class檔案,當系統運作時,此class已經存在。這種靜态的代理模式在增強現有的接口業務功能方面有很大的優點,但是大量使用靜态代理,會使系統内的類大規模爆發,不易維護。

為了解決這個問題,就有了動态建立Proxy的想法,在運作狀态中,動态的建立一個Proxy代理類,使用完之後就會銷毀,這樣就不用維護大量的代理類。

靜态代理案例

建立一個車票接口,定義一個賣票的方法。

package com.doaredo.test.proxy;

public interface Ticket {
    public void sell();
}
           

建立一個車站類,實作賣票的接口,讓其擁有賣票的功能。

package com.doaredo.test.proxy;

public class Station implements Ticket {
    @Override
    public void sell() {
        System.out.println("車站售票");
    }
}
           

建立一個售票代理類,實作車票接口,通過構造函數注入車站類,讓其可以代理車站售票。

package com.doaredo.test.proxy;

public class StationProxy implements Ticket {
    private Station station;

    // 構造函數注入車站類,使其擁有售票功能
    public StationProxy(Station station){
        this.station = station;
    }

    @Override
    public void sell() {
        System.out.println("代理點開始售票");
        station.buy();
        System.out.println("代理點售票完成");
    }
}
           

建立測試類,使用售票代理類來完成售票。

package com.doaredo.test.proxy;

import sun.misc.ProxyGenerator;

import java.io.FileOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class Test {

    public static void main(String[] args) throws Exception {
        // 通過構造函數傳入車站對象,使代理對象擁有售票功能
        StationProxy stationProxy = new StationProxy(new Station());
        stationProxy.sell();
    }

}
           

靜态代理比較簡單,代理類隻需要實作目标類的接口,然後通過構造函數注入目标類,這樣便可以完成目标類方法的調用,代理類可以在目标方法執行的前後做一些額外的功能,進而實作代理功能。

InvocationHandler的由來

代理就是在調用目标方法之前或者之後做一些額外的功能,但是我們在寫完代理類後,還需要再去調用指定的目标方法,上面靜态代理的目标方法為sell方法,這個目标方法是由我們自己定義的,不能統一。

為了構造出具有通用性和簡單性的代理類,于是将調用目标方法統一交給一個管理器,讓這個管理器統一的調用目标方法。這個管理器就是InvocationHandler。由于目标方法名稱不同,怎麼才能統一調用呢?在Java中使用反射就可以來實作統一的調用目标方法,将目标方法統一為反射中的Method。

JDK動态代理

使用JDK動态代理來實作本站售票的代理類。

建立一個車票接口,定義一個賣票的方法。

package com.doaredo.test.proxy;

public interface Ticket {
    public void sell();
}
           

建立一個車站類,實作賣票的接口,讓其擁有賣票的功能。

package com.doaredo.test.proxy;

public class Station implements Ticket {
    @Override
    public void sell() {
        System.out.println("車站售票");
    }
}
           

建立InvocationHandler的實作類,通過構造函數注入目标類(即被代理的類,這裡Station車站類将被代理)。

實作invoke方法,Method參數就是要執行的目标方法,通過method.invoke進而完成目标方法的調用,在目标方法調用的前後來完成代理功能。

package com.doaredo.test.proxy;

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

public class InvocationHandlerImpl implements InvocationHandler {
    private Station station;

    public InvocationHandlerImpl(Station station){
        this.station = station;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("jdk動态代理開始");
        method.invoke(station, args);
        System.out.println("jdk動态代理結束");
        return null;
    }
}
           

建立測試類,完成JDK動态代理的調用,同時将JDK動态生成的代理類的class檔案輸出。

  • 既然JDK要動态的幫我們生成代理類,動态的生成代理類後需要進行加載,是以需要一個類加載器ClassLoader。
  • 需要目标類實作的接口。(為什麼要接口?)
  • 執行目标方法,完成代理功能的管理類,InvocationHandler的實作。
package com.doaredo.test.proxy;

import sun.misc.ProxyGenerator;

import java.io.FileOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class Test {

    public static void main(String[] args) throws Exception {
        Station station = new Station();
        // 類加載器
        ClassLoader classLoader = station.getClass().getClassLoader();
        // 接口資訊
        Class[] interfaces = station.getClass().getInterfaces();
        // InvocationHandler的實作,完成代理功能,執行目标方法
        InvocationHandler handler = new InvocationHandlerImpl(station);
        // Jdk動态生成代理對象
        Object o = Proxy.newProxyInstance(classLoader,interfaces,handler);
        Ticket ticket = (Ticket)o;
        ticket.sell();
        generateClassFile(station.getClass(), "JdkProxyStation");
    }

    // 生成class檔案
    public static void generateClassFile(Class clazz, String proxyName) throws Exception {
        byte[] bytes = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces());
        String path = clazz.getResource(".").getPath();
        FileOutputStream fos = new FileOutputStream(path + proxyName + ".class");
        fos.write(bytes);
        fos.flush();
        fos.close();
    }
}
           

使用Jdk動态代理,并生成動态産生的代理類的class檔案,通過反編譯檢視生成的代碼如下:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

import com.doaredo.test.proxy.Ticket;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class JdkProxyStation extends Proxy implements Ticket {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public JdkProxyStation(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void sell() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.doaredo.test.proxy.Ticket").getMethod("sell");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
           

我們可以看到,Jdk生成的代理類都繼承了Proxy,同時實作了我們目标類的接口,其中m3就是要執行的目标方法。其它的都是Object類中的方法。我們看一下是怎麼執行目标方法的:

super.h其實就是指的Proxy中的InvocationHandler,也就是在這裡将m3傳遞給了InvocationHandler的invoke方法,進而可以通過m3來完成目标方法的調用。

平時我們看的資料都說Jdk動态代理隻能是接口,這下大家都知道原因了吧,因為Java是單繼承的,而Jdk動态代理中,Jdk自己已經繼承了Proxy,是以我們不能再使用繼承了,而隻能使用接口的形式。

代理類特點:

  1. 繼承自Proxy,實作了定義的接口
  2. 類中的所有方法都是final的
  3. 所有的方法實作都統一調用了InvocationHandler的invoke()方法

Cglib動态代理

Jdk提供的動态代理有個特點:某個類必須有實作的接口,而生成的代理類也隻能代理接口定義的方法。也就是說,如果某個類沒有實作接口,那麼這個類就不能使用Jdk産生動态代理了。

Cglib可以在沒有接口的情況下完成動态代理,原理差不多,後面我們自己來生成代理類實作代理功能。

下面是Cglib的使用:

<?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>idea-demo</groupId>
    <artifactId>idea-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <!--sm包 -->
        <dependency>
            <groupId>org.ow2.asm</groupId>
            <artifactId>asm</artifactId>
            <version>8.0.1</version>
        </dependency>
        <!-- cglib包 -->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
             <version>3.3.0</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>
    
</project>
           
package com.doaredo.test.proxy;

public class CglibStation {

    public void sell() {
        System.out.println("車站售票");
    }

}
           
package com.doaredo.test.proxy;

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

import java.lang.reflect.Method;

public class CglibProxy implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib代理開始");
        methodProxy.invokeSuper(o, objects);
        System.out.println("cglib代理結束");
        return null;
    }
}
           
package com.doaredo.test.proxy;

import net.sf.cglib.proxy.Enhancer;
import sun.misc.ProxyGenerator;

import java.io.FileOutputStream;

public class Test {

    public static void main(String[] args) throws Exception {
        CglibStation cglibStation = new CglibStation();
        CglibProxy cglibProxy = new CglibProxy();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(cglibStation.getClass());
        enhancer.setCallback(cglibProxy);
        CglibStation proxy = (CglibStation) enhancer.create();
        proxy.sell();
    }
}
           

更深層次了解動态代理

要明白動态代理,不能隻是表面的怎麼使用動态代理,記住一點,動态代理最重要的就是:動态的建立一個類,加入需要添加的邏輯代碼,并且執行被代理對象的邏輯。

既然是動态的建立類,據我所知,操作Java常用的有Javassist和ASM,Javassist相對ASM使用上比較簡單,下面就使用Javassist來學習動态代理模式是怎麼實作的。

加入javassist依賴

<dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.21.0-GA</version>
</dependency>
           

定義接口

// 先定義一個接口
public interface Service {
    public void hello(String msg);
    public void bye(String name);
}
           

使用javassist動态建立類,注意:并非是代理類,是用javassist動态建立Service接口的實作類:

  • 建立一個ServiceImpl類,實作Service接口
  • 在實作類的hello方法中,輸出hello+msg參數,在javassist中,$1表示第一個參數
package com.doaredo.test.proxy;

import javassist.*;
import org.junit.Test;

public class JavassistProxy {

    @Test
    public void test() throws Exception {
        ClassPool classPool = ClassPool.getDefault();
        // 建立一個類
        CtClass clazz = classPool.makeClass("ServiceImpl");
        // 擷取定義的接口,轉換成CtClass
        CtClass interfaceCtClass = classPool.get(Service.class.getName());
        // 給類添加接口
        clazz.addInterface(interfaceCtClass);
        // 邏輯代碼
        String code = "{System.out.println(\"hello:\"+$1);}";
        // String類型的CtClass
        CtClass stringCtClass = classPool.get(String.class.getName());
        // 實作接口中的hello方法
        CtMethod hello = CtNewMethod.make(CtClass.voidType, "hello",
                new CtClass[]{stringCtClass},// 參數
                new CtClass[0],// 異常
                code,// 邏輯代碼
                clazz);// 實作方法的類
        clazz.addMethod(hello);
        // 将CtClass轉換成Java的Class
        Class cla = classPool.toClass(clazz);
        // 執行個體化Class執行對應的方法
        Service service = (Service) cla.newInstance();
        service.hello("doaredo");
    }
}
           

上面利用Javassist動态的建立了一個類,并且實作了Service接口的hello方法,但是有幾個問題:

  • 擷取定義接口的時候,Service.class.getName()是寫死的,如果接口不叫Service那麼就不好使了
  • 邏輯代碼是通過手寫的,編譯器無法識别,容易出錯

改進後代碼如下:

  • 将接口和邏輯代碼都通過參數形式傳遞進來
package com.doaredo.test.proxy;

import javassist.*;
import org.junit.Test;

public class JavassistProxy {

    public static <T> T createClass(Class<T> interfaceClass, String code) throws Exception {
        ClassPool classPool = ClassPool.getDefault();
        // 建立一個類
        CtClass clazz = classPool.makeClass("ServiceImpl");
        // 擷取定義的接口,轉換成CtClass
        CtClass interfaceCtClass = classPool.get(interfaceClass.getName());
        // 給類添加接口
        clazz.addInterface(interfaceCtClass);
        // String類型的CtClass
        CtClass stringCtClass = classPool.get(String.class.getName());
        CtMethod hello = CtNewMethod.make(CtClass.voidType, "hello",
                new CtClass[]{stringCtClass},// 參數
                new CtClass[0],// 異常
                code,// 邏輯代碼
                clazz);// 實作方法的類
        clazz.addMethod(hello);
        // 執行個體化Class
        Class cla = classPool.toClass(clazz);
        return (T) cla.newInstance();
    }

    @Test
    public void test2() throws Exception {
        Service service = createClass(Service.class,"{System.out.println(\"hello:\"+$1);}");
        service.hello("doaredo");
        // 缺點:換方法後不能用了
        //service.bye("doaredo");
    }
}
           

經過改進後發現這裡hello方法與是寫死的,我們的目的是要能代理接口的所有方法,以及自定義邏輯代碼。既然要自定義邏輯代碼,那麼就定義一個執行邏輯代碼的接口,将邏輯代碼以參數形式傳遞進來。

public interface InvocationHandler {
    Object invoke(String method, Object args[]);
}
           

接下來動态的實作接口中的所有的方法:

  • 建立接口的實作類
  • 給類添加InvocationHandler屬性,通過InvocationHandler可以調用實作的邏輯代碼
  • 周遊接口中所有的方法,并實作所有的方法,所有方法都調用InvocationHandler的invoke方法來執行代理邏輯以及目标方法
  • 将InvocationHandler實作類注入到handler屬性中
  • $args是javassist中的文法,相當于Object args[]
package com.doaredo.test.proxy;

import javassist.*;
import org.junit.Test;

import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.stream.Collectors;

public class JavassistProxy {

	private static int count = 0;
    
    public static<T> T proxy(Class<T> interfaceClass, InvocationHandler h) throws Exception {
        ClassPool classPool = ClassPool.getDefault();
        // 建立一個類
        CtClass clazz = classPool.makeClass("&proxy&"+(count++)+"."+interfaceClass.getName());
        clazz.addInterface(classPool.get(interfaceClass.getName()));
        // 添加handler屬性
        CtField ctField = CtField.make("public com.doaredo.test.proxy.JavassistProxy.InvocationHandler handler=null;", clazz);
        clazz.addField(ctField);
        // 周遊接口中的所有方法,并實作接口中的方法
        for (Method m : interfaceClass.getMethods()){
            // 擷取方法的傳回類型
            CtClass returnType = classPool.get(m.getReturnType().getName());
            // 擷取方法名稱
            String name = m.getName();
            // 擷取方法參數
            CtClass[] parameters = ctClass(classPool, m.getParameterTypes());
            // 擷取異常
            CtClass[] errors = ctClass(classPool, m.getExceptionTypes());
            String code = "";
            if(Void.class.equals(returnType)){
                // 沒有傳回值
                code = "this.handler.invoke(\"%s\", $args);";
            }else{
                code = "return ($r)this.handler.invoke(\"%s\", $args);";
            }
            // 實作接口中的方法
            CtMethod hello = CtNewMethod.make(returnType, name,
                    parameters,
                    errors,
                    String.format(code, m.getName()),
                    clazz);
            clazz.addMethod(hello);
        }
        // 将CtClass轉換成Java的Class
        Class cla = classPool.toClass(clazz);
        // 執行個體化Class
        Object o = cla.newInstance();
        // 擷取執行個體化類的handler屬性,并且指派為h。h為傳入進來的邏輯代碼實作類
        cla.getField("handler").set(o, h);

        // 将生成的類的代碼寫入到項目的target目錄下
        byte[] bytes = clazz.toBytecode();
        Files.write(Paths.get(System.getProperty("user.dir") + "/target/" + clazz.getName() + ".class"), bytes);
        return (T) o;
    }

    private static CtClass[] ctClass(ClassPool cp, Class[] classes) {
        CtClass[] result = Arrays.stream(classes).map(c -> {
            try {
                return cp.get(c.getName());
            } catch (NotFoundException e) {
                e.printStackTrace();
            }
            return null;
        }).collect(Collectors.toList()).toArray(new CtClass[0]);
        return result;
    }
    
    @Test
    public void test3() throws Exception {
        Service service = proxy(Service.class, new InvocationHandler() {
            @Override
            public Object invoke(String method, Object[] args) {
                if(method.equals("hello")){
                    System.out.println("hello " + args[0]);
                }else if(method.equals("bye")){
                    System.out.println("bye " + args[0]);
                }
                return null;
            }
        });
        service.hello("doaredo");
        service.bye("doaredo");
    }

}
           

注意上面invoke方法中的method參數,是一個String類型,需要通過判斷具體方法名稱來決定具體的代理邏輯,顯然不太合适,注意:上面隻是利用Javassist動态的給Service接口建立了一個實作類,并沒有給哪個類做代理。

下面我們稍微改造一下代碼,來對具體的實作類進行動态代理:

package com.doaredo.test.proxy;

import javassist.*;
import org.junit.Test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.stream.Collectors;

public class JavassistProxy {

    /**
     * 支援所有接口代理
     * 不直接傳代碼,容易出錯
     */
    private static int count = 0;
    public static<T> T proxy(Class<T> interfaceClass, InvocationHandler h) throws Exception {
        ClassPool classPool = ClassPool.getDefault();
        // 建立一個類
        CtClass clazz = classPool.makeClass("&proxy&"+(count++)+"."+interfaceClass.getName());
        clazz.addInterface(classPool.get(interfaceClass.getName()));
        // 添加handler屬性
        CtField ctField = CtField.make("public com.doaredo.test.proxy.JavassistProxy.InvocationHandler handler=null;", clazz);
        clazz.addField(ctField);
        // 周遊接口中的所有方法,并實作接口中的方法
        Method[] methods = interfaceClass.getMethods();
        for (int i = 0; i < methods.length; i++){
            Method m = methods[i];
            // 擷取方法的傳回類型
            CtClass returnType = classPool.get(m.getReturnType().getName());
            // 擷取方法名稱
            String name = m.getName();
            // 擷取方法參數
            CtClass[] parameters = ctClass(classPool, m.getParameterTypes());
            // 擷取異常
            CtClass[] errors = ctClass(classPool, m.getExceptionTypes());
            String code = "";
            String methodFieldTpl = "private static java.lang.reflect.Method %s=Class.forName(\"%s\").getDeclaredMethod(\"%s\", %s);";
            String classParams = "new Class[0]";
            if (m.getParameterTypes().length>0) {
                for (Class param : m.getParameterTypes()){
                    classParams = classParams.equals("new Class[0]") ? param.getName() + ".class" : classParams + "," + param.getName() + ".class";
                }
                classParams = "new Class[]{"+classParams+"}";
            }
            // 方法字段
            String methodFieldBody = String.format(methodFieldTpl, "m" + i, interfaceClass.getName(), m.getName(), classParams);
            // 為代理類添加反射方法字段
            CtField methodField=CtField.make(methodFieldBody,clazz);
            clazz.addField(methodField);

            if(Void.class.equals(returnType)){
                // 沒有傳回值
                // $0=this / $1,$2,$3... 代表方法參數
                code = "&0.handler.invoke("+methodField.getName()+", $args);";
            }else{
                code = "return ($r)this.handler.invoke("+methodField.getName()+", $args);";
            }
            // 實作接口中的方法
            CtMethod hello = CtNewMethod.make(returnType, name,
                    parameters,
                    errors,
                    String.format(code, m),
                    clazz);
            clazz.addMethod(hello);
        }
        // 将生成的類的代碼寫入到項目的target目錄下
        byte[] bytes = clazz.toBytecode();
        Files.write(Paths.get(System.getProperty("user.dir") + "/target/" + clazz.getName() + ".class"), bytes);

        // 将CtClass轉換成Java的Class
        Class cla = classPool.toClass(clazz);
        // 執行個體化Class
        Object o = cla.newInstance();
        // 擷取執行個體化類的handler屬性,并且指派為h。h為傳入進來的邏輯代碼實作類
        cla.getField("handler").set(o, h);
        return (T) o;
    }

    private static CtClass[] ctClass(ClassPool cp, Class[] classes) {
        CtClass[] result = Arrays.stream(classes).map(c -> {
            try {
                return cp.get(c.getName());
            } catch (NotFoundException e) {
                e.printStackTrace();
            }
            return null;
        }).collect(Collectors.toList()).toArray(new CtClass[0]);
        return result;
    }

    @Test
    public void test3() throws Exception {
        Service service = proxy(Service.class, new InvocationHandlerImpl(new ServiceImpl()));
        service.hello("doaredo");
        service.bye("doaredo");
    }

    // 實作代理接口,完成代理邏輯
    public class InvocationHandlerImpl implements InvocationHandler {
        private Service service;

        public InvocationHandlerImpl(Service service) {
            this.service = service;
        }
        @Override
        public Object invoke(Method method, Object[] args) {
            try {
                System.out.println("代理前");
                // 通過反射執行被代理對象的方法
                method.invoke(service, args);
                System.out.println("代理後");
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

    // 代理類接口
    public interface InvocationHandler {
        Object invoke(Method method, Object args[]);
    }

    // 服務接口
    public interface Service {
        public void hello(String msg);
        public void bye(String name);
    }

    // 服務實作
    public class ServiceImpl implements Service {

        @Override
        public void hello(String msg) {
            System.out.println("hello " + msg);
        }

        @Override
        public void bye(String name) {
            System.out.println("bye " + name);
        }
    }

}
           

下面就是使用Javassist來實作JDK的動态代理,反編譯生成的代碼如下:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package &proxy&0.com.doaredo.test.proxy;

import com.doaredo.test.proxy.JavassistProxy.InvocationHandler;
import com.doaredo.test.proxy.JavassistProxy.Service;
import java.lang.reflect.Method;

public class JavassistProxy$Service implements Service {
    public InvocationHandler handler = null;
    private static Method m0 = Class.forName("com.doaredo.test.proxy.JavassistProxy$Service").getDeclaredMethod("hello", String.class);
    private static Method m1 = Class.forName("com.doaredo.test.proxy.JavassistProxy$Service").getDeclaredMethod("bye", String.class);

    public void hello(String var1) {
        this.handler.invoke(m0, new Object[]{var1});
    }

    public String bye(String var1) {
        return (String)this.handler.invoke(m1, new Object[]{var1});
    }

    public JavassistProxy$Service() {
    }
}
           

初次看會覺得比較繞,前面Jdk生成的代理類跟我們自己生成的代理類原理都是一樣的,但是Jdk中還生成了Object類中的所有方法,同時繼承了Proxy類。