RE|GoF23種設計模式-動態代理

代理模式

定義

代理(Proxy)是一種設計模式,提供了對目標對象另外的訪問方式;即經過代理對象訪問目標對象.這樣作的好處是:能夠在目標對象實現的基礎上,加強額外的功能操做,即擴展目標對象的功能。符合開閉原則。代理模式屬於結構型 模式,有靜態代理和動態代理。java

靜態代理

需求:如今咱們須要根據類型來分別把數據上傳到不一樣Ftp服務。設計模式

/** * 數據的模型類 */
public static class Data {

    private Integer type;
    private String name;
    private String sex;

    public Integer getType() {
        return type;
    }

    public void setType(Integer type) {
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

}


public static interface IFTPService {
    void upload(Data data);
}

public static class FTPService implements IFTPService {

    @Override
    public void upload(Data data) {
        System.out.println("Data{" +
                "type=" + data.getType() +
                ", name='" + data.getName() + '\'' +
                ", sex='" + data.getSex() + '\'' +
                '}');
    }

}

public static class FTPServiceStaticProxy implements IFTPService {

    private IFTPService ftpService;

    // 靜態代理 構造注入的方式賦值
    public FTPServiceStaticProxy(IFTPService ftpService) {
        this.ftpService = ftpService;
    }

    @Override
    public void upload(Data data) {
        before();
        if (data.getType() % 2 == 0) {
            System.out.println("上傳到服務器 1");
            ftpService.upload(data);
        } else {
            System.out.println("上傳到服務器 2");
            ftpService.upload(data);
        }
        after();
    }

    private void before(){
        System.out.println("Proxy before method.");
    }
    private void after(){
        System.out.println("Proxy after method.");
    }
}


public static void main(String[] args) {
    Data data = new Data();
    data.setName("Name Zhuang San");
    data.setSex("男");
    data.setType(1);
    new FTPServiceStaticProxy(new FTPService()).upload(data);

    Data data2 = new Data();
    data.setName("Name Wan Wu");
    data.setSex("男");
    data.setType(2);
    new FTPServiceStaticProxy(new FTPService()).upload(data);
}

複製代碼

動態代理

動態代理有如下特色:數組

  1. 代理對象,不須要實現接口
  2. 代理對象的生成,是利用JDK的API,動態的在內存中構建代理對象(須要咱們指定建立代理對象/目標對象實現的接口的類型)
  3. 動態代理也叫作: JDK代理,接口代理

JDK 實現方式

/** * 數據的模型類 */
public static class Data {

    private Integer type;
    private String name;
    private String sex;

    public Integer getType() {
        return type;
    }

    public void setType(Integer type) {
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

}

public static interface IFTPService {
    void upload(Data data);
}

public static class FTPService implements IFTPService {

    @Override
    public void upload(Data data) {
        System.out.println("Data{" +
                "type=" + data.getType() +
                ", name='" + data.getName() + '\'' +
                ", sex='" + data.getSex() + '\'' +
                '}');
    }

}

public static class JDKProxyFTPService implements InvocationHandler {

    private Object target;

    public Object upload(Object target) {
        this.target = target;
        Class<?> clazz = target.getClass();
        // 如何實現的代理?
        return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 只讓 upload 方法進入
        if (!"upload".equals(method.getName())) return method.invoke(target, args);
        before(args[0]);
        Object r = method.invoke(target, args);
        after();
        return r;
    }

    private void before(Object data){
        System.out.println("Proxy before method.");
        if (data instanceof Data) { // 判斷是否屬於 -- Data 模型
            Data d = (Data) data;
            if (d.getType() % 2 == 0)
                System.out.println("上傳到服務器 1");
            else
                System.out.println("上傳到服務器 2");
        }
    }
    private void after(){
        System.out.println("Proxy after method.");
    }


}

public static void main(String[] args) {
    IFTPService ftpService = (IFTPService) new JDKProxyFTPService().upload(new FTPService());
    Data data = new Data();
    data.setName("Name Zhuang San");
    data.setSex("男");
    data.setType(1);
    ftpService.upload(data);
}

複製代碼

Proxy 是如何實現的呢?

咱們都知道 JDK Proxy 採用字節重組,從新生的對象來替代原始的對象以達到動態代理的目的。JDK Proxy 生成對象的步驟以下:服務器

  1. 拿到被代理對象的引用,而且獲取到它的全部的接口,反射獲取。
  2. JDK Proxy 類從新生成一個新的類、同時新的類要實現被代理類全部實現的全部的接口。
  3. 動態生成 Java 代碼,把新加的業務邏輯方法由必定的邏輯代碼去調用(在代碼中體現)。
  4. 編譯新生成的 Java 代碼.class。
  5. 再從新加載到 JVM 中運行。
public static void main(String[] args) throws IOException {
    //經過反編譯工具能夠查看源代碼
    byte [] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{IFTPService.class});
    FileOutputStream os = new FileOutputStream("E://$Proxy0.class");
    os.write(bytes);
    os.close();
}

複製代碼

使用反編譯工具,獲得java代碼以下:app

package com.reape.design.pattern.proxy;

import java.lang.reflect.*;
import com.reape.design.pattern.proxy.*;

// 繼承了Proxy類 接口咱們的 JDKIFTPService
public final class $Proxy0 extends Proxy implements JDKIFTPService {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public $Proxy0(final InvocationHandler invocationHandler) {
        super(invocationHandler);
    }

    // 重寫了 toString hashCode equals 指向了原來的地址
    public final boolean equals(final Object o) {
        try {
            return (boolean)super.h.invoke(this, $Proxy0.m1, new Object[] { o });
        }
        catch (Error | RuntimeException error) {
            throw new Error();
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }

    public final void upload(final JDKData jdkData) {
        try {
            super.h.invoke(this, $Proxy0.m3, new Object[] { jdkData });
        }
        catch (Error | RuntimeException error) {
            throw new Error();
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }

    public final String toString() {
        try {
            return (String)super.h.invoke(this, $Proxy0.m2, null);
        }
        catch (Error | RuntimeException error) {
            throw new Error();
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }

    public final int hashCode() {
        try {
            return (int)super.h.invoke(this, $Proxy0.m0, null);
        }
        catch (Error | RuntimeException error) {
            throw new Error();
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }

    static {
        try {
            $Proxy0.m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            $Proxy0.m3 = Class.forName("com.reape.design.pattern.proxy.JDKIFTPService").getMethod("upload", Class.forName("com.reape.design.pattern.proxy.JDKData"));
            $Proxy0.m2 = Class.forName("java.lang.Object").getMethod("toString", (Class<?>[])new Class[0]);
            $Proxy0.m0 = Class.forName("java.lang.Object").getMethod("hashCode", (Class<?>[])new Class[0]);
        }
        catch (NoSuchMethodException ex) {
            throw new NoSuchMethodError(ex.getMessage());
        }
        catch (ClassNotFoundException ex2) {
            throw new NoClassDefFoundError(ex2.getMessage());
        }
    }
}

複製代碼

手寫動態代理

// 1. ClassLoader 自定義

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class MyClassLoader extends ClassLoader{

    private File classPathFile;

    public MyClassLoader(){
        String classPath = MyClassLoader.class.getResource("").getPath();
        this.classPathFile = new File(classPath);
    }
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        String className = MyClassLoader.class.getPackage().getName() + "." + name;
        if(classPathFile != null){
            File classFile = new File(classPathFile,name.replaceAll("\\.","/") + ".class");
            if(classFile.exists()){
                FileInputStream in = null;
                ByteArrayOutputStream out = null;
                try{
                    in = new FileInputStream(classFile);
                    out = new ByteArrayOutputStream();
                    byte [] buff = new byte[1024];
                    int len;
                    while ((len = in.read(buff)) != -1){
                        out.write(buff,0,len);
                    }
                    return defineClass(className,out.toByteArray(),0,out.size());
                }catch (Exception e){
                    e.printStackTrace();
                }finally {
                    if(null != in){
                        try {
                            in.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if(out != null){
                        try {
                            out.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        return null;
    }
}

// 2. 動態代理實現的接口類
import java.lang.reflect.Method;

/** * 動態代理實現的接口類 */
public interface MyInvocationHandler {

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

}


3. 生成java文件編譯爲class寫入jvm,動態代理 /** * 用來生成源代碼的工具類 */ public class MyProxy {


    private static final String ln = "\r\n";
    private static final String t = "\t";

    public static Object newProxyInstance(MyClassLoader classLoader, Class<?> [] interfaces, MyInvocationHandler h){
        try {
            // 1.動態生成源代碼文件
            String src = generateSrc(interfaces);

            //二、Java 文件輸出磁盤
            String filePath = MyProxy.class.getResource("").getPath();
            System.out.println(filePath);
            File f = new File(filePath + "$Proxy0.java");
            FileWriter fw = null;
            fw = new FileWriter(f);
            fw.write(src);
            fw.flush();
            fw.close();
            //三、把生成的.java 文件編譯成.class 文件
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager manage = compiler.getStandardFileManager(null,null,null);
            Iterable iterable = manage.getJavaFileObjects(f);
            JavaCompiler.CompilationTask task =
                    compiler.getTask(null,manage,null,null,null, iterable);
            task.call();
            manage.close();
            //四、編譯生成的.class 文件加載到 JVM 中來
            Class<Object> proxyClass = (Class<Object>) classLoader.findClass("$Proxy0");
            Constructor<Object> c = proxyClass.getConstructor(MyInvocationHandler.class);
// f.delete();
            //五、返回字節碼重組之後的新的代理對象
            return c.newInstance(h);
        } catch (IOException | InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static String generateSrc(Class<?>[] interfaces){
        // interfaces ---> 須要實現的接口的類
        StringBuilder sb = new StringBuilder();
        sb.append("package com.reape.design.pattern.proxy.handwriting;" + ln);
        sb.append("import java.lang.reflect.*;" + ln);
        sb.append("public class $Proxy0 implements").append(interfacesToString(interfaces));
        sb.append(" {").append(ln);
        sb.append(t + "private com.reape.design.pattern.proxy.handwriting.MyInvocationHandler h;" + ln);
        sb.append(t + "public $Proxy0(com.reape.design.pattern.proxy.handwriting.MyInvocationHandler h) { " + ln);
        sb.append(t + t + "this.h = h;" + ln);
        sb.append(t + "}" + ln);
        for (Class<?> anInterface : interfaces) {
            for (Method m : anInterface.getMethods()) {
                Class<?>[] params = m.getParameterTypes();
                Class<?> result = m.getReturnType();
                sb.append(t + "public final ")
                        .append(resultToString(result))
                        .append(" ")
                        .append(m.getName())
                        .append("(")
                        .append(paramsToString(params))
                        .append(") {").append(ln);
                sb.append(t + t + "try {" + ln);
                sb.append(t + t + t)
                        .append(returnToString(result))
                        .append("h.invoke(this, " + "Class.forName(\"")
// .append(anInterface.getName())
                        .append("com.reape.design.pattern.proxy.JDKFTPService")
                        .append("\")")
                        .append(".getMethod(").append("\"").append(m.getName()).append("\"").append(", ")
                        .append(paramsFormNameToString(params))
                        .append(")").append(", new Object[]{ p0 });").append(ln);
                sb.append(t + t + "}" + ln);
                sb.append(t + t + "catch(Error | RuntimeException error) { error.printStackTrace();" + ln);
                sb.append(t + t + t + "throw new Error();" + ln);
                sb.append(t + t + "}" + ln);
                sb.append(t + t + "catch (Throwable t) {" + ln);
                sb.append(t + t + t + "throw new UndeclaredThrowableException(t);" + ln);
                sb.append(t + t + "}" + ln);
                sb.append(t + "}" + ln);
            }
        }
        sb.append("}" + ln);
        return sb.toString();
    }

    /** * 接口類數組轉 String * @param interfaces 接口類數組 * @return 字符串 */
    private static String interfacesToString(Class<?>[] interfaces) {
        if (interfaces.length < 1) return "";
        StringBuilder sb = new StringBuilder();
        for (Class<?> anInterface : interfaces) {
            sb.append(" ").append(anInterface.getName()).append(",");
        }
        return sb.substring(0, sb.length() - 1);
    }


    private static String paramsToString(Class<?>[] params) {
        if (params.length < 1) return "";
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < params.length; i++) {
            sb.append(params[i].getName()).append(" ").append("p").append(i).append(", ");
        }
        return sb.substring(0, sb.length() - 2);
    }

    private static String paramsFormNameToString(Class<?>[] params) {
        if (params.length < 1) return "";
        StringBuilder sb = new StringBuilder();
        for (Class<?> param : params) {
            sb.append("Class.forName(\"").append(param.getName()).append("\"), ");
        }
        return sb.substring(0, sb.length() - 2);
    }


    private static String resultToString(Class<?> result) {
        String name = result.getName();
        return "void".equals(name) ? "void" : name;
    }

    private static String returnToString(Class<?> result) {
        String name = result.getName();
        return "void".equals(name) ? "" : "return (" + name + ") ";
    }

}

// 4.測試



public class Test implements MyInvocationHandler {

    private Object target;

    public Object get(Object target) {
        this.target = target;
        Class<?> clazz = target.getClass();
        return MyProxy.newProxyInstance(new MyClassLoader(), clazz.getInterfaces(), this);
    }

    private void before(Object data){
        System.out.println(data);
        System.out.println("Proxy before method.");
    }
    private void after(){
        System.out.println("Proxy after method.");
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 只讓 upload 方法進入
        if (!"upload".equals(method.getName())) return method.invoke(target, args);
        before(args[0]);
        Object r = method.invoke(target, args);
        after();
        return r;
    }


    public static void main(String[] args) {
        JDKIFTPService ftpService = (JDKIFTPService) new Test().get(new JDKFTPService());
        JDKData data = new JDKData();
        data.setName("Name Zhuang San");
        data.setSex("男");
        data.setType(1);
        ftpService.upload(data);
    }

}

// 上面的代碼寫考慮的不是很完整
// 有不少判斷的地方沒有判斷以及重寫 toString ,equals 等

// java的代理是編譯爲class文件而後寫入的到jvm節約的了內存消耗,可是跟cglib對比仍是差很遠
// cglib是字節碼操做

複製代碼

CGLib實現

// 導入jar包
// 1. asm.jar
// 2. cglib.jar


public class JDKData {
    private Integer type;
    private String name;
    private String sex;

    public Integer getType() {
        return type;
    }

    public void setType(Integer type) {
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}


public class JDKFTPService implements JDKIFTPService {

    @Override
    public void upload(JDKData data) {
        System.out.println("Data{" +
                "type=" + data.getType() +
                ", name='" + data.getName() + '\'' +
                ", sex='" + data.getSex() + '\'' +
                '}');
    }
}




public class CglibJDK implements MethodInterceptor {

    public Object getInstance(Class<?> clazz) throws Exception{
        Enhancer enhancer = new Enhancer();
        //要把哪一個設置爲即將生成的新類父類
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //業務的加強
        before(objects[0]);
        Object obj = methodProxy.invokeSuper(o,objects);
        after();
        return obj;
    }


    private void before(Object data){
        System.out.println("Proxy before method.");
        System.out.println(data);
        if (data instanceof JDKData) { // 判斷是否屬於 -- Data 模型
            JDKData d = (JDKData) data;
            if (d.getType() % 2 == 0)
                System.out.println("上傳到服務器 1");
            else
                System.out.println("上傳到服務器 2");
        }
    }
    private void after(){
        System.out.println("Proxy after method.");
    }
}


// 測試
public static void main(String[] args) {
    try {
        JDKFTPService obj = (JDKFTPService) new CglibJDK().getInstance(JDKFTPService.class);
        JDKData data = new JDKData();
        data.setName("Name Zhuang San");
        data.setSex("男");
        data.setType(1);
        obj.upload(data);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

// 編譯獲得class文件

package com.reape.design.pattern.proxy.cglib;

import net.sf.cglib.reflect.*;
import net.sf.cglib.core.*;
import net.sf.cglib.proxy.*;
import java.lang.reflect.*;

public class JDKFTPService$$EnhancerByCGLIB$$5a7831ef$$FastClassByCGLIB$$5a694231 extends FastClass {
    public JDKFTPService$$EnhancerByCGLIB$$5a7831ef$$FastClassByCGLIB$$5a694231(final Class clazz) {
        super(clazz);
    }
    
    public int getIndex(final Signature signature) {
        final String string = signature.toString();
        switch (string.hashCode()) {
            case -2055565910: {
                if (string.equals("CGLIB$SET_THREAD_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
                    return 12;
                }
                break;
            }
            case -1882565338: {
                if (string.equals("CGLIB$equals$1(Ljava/lang/Object;)Z")) {
                    return 15;
                }
                break;
            }
            case -1457535688: {
                if (string.equals("CGLIB$STATICHOOK1()V")) {
                    return 19;
                }
                break;
            }
            case -1411842725: {
                if (string.equals("CGLIB$hashCode$3()I")) {
                    return 18;
                }
                break;
            }
            case -894172689: {
                if (string.equals("newInstance(Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
                    return 6;
                }
                break;
            }
            case -623122092: {
                if (string.equals("CGLIB$findMethodProxy(Lnet/sf/cglib/core/Signature;)Lnet/sf/cglib/proxy/MethodProxy;")) {
                    return 20;
                }
                break;
            }
            case -508378822: {
                if (string.equals("clone()Ljava/lang/Object;")) {
                    return 3;
                }
                break;
            }
            case -419626537: {
                if (string.equals("setCallbacks([Lnet/sf/cglib/proxy/Callback;)V")) {
                    return 11;
                }
                break;
            }
            case 560567118: {
                if (string.equals("setCallback(ILnet/sf/cglib/proxy/Callback;)V")) {
                    return 7;
                }
                break;
            }
            case 773140094: {
                if (string.equals("CGLIB$upload$0(Lcom/reape/design/pattern/proxy/cglib/JDKData;)V")) {
                    return 14;
                }
                break;
            }
            case 811063227: {
                if (string.equals("newInstance([Ljava/lang/Class;[Ljava/lang/Object;[Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
                    return 5;
                }
                break;
            }
            case 840180909: {
                if (string.equals("upload(Lcom/reape/design/pattern/proxy/cglib/JDKData;)V")) {
                    return 8;
                }
                break;
            }
            case 973717575: {
                if (string.equals("getCallbacks()[Lnet/sf/cglib/proxy/Callback;")) {
                    return 10;
                }
                break;
            }
            case 1221173700: {
                if (string.equals("newInstance([Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
                    return 4;
                }
                break;
            }
            case 1230699260: {
                if (string.equals("getCallback(I)Lnet/sf/cglib/proxy/Callback;")) {
                    return 9;
                }
                break;
            }
            case 1306468936: {
                if (string.equals("CGLIB$toString$2()Ljava/lang/String;")) {
                    return 16;
                }
                break;
            }
            case 1584330438: {
                if (string.equals("CGLIB$SET_STATIC_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
                    return 13;
                }
                break;
            }
            case 1800494055: {
                if (string.equals("CGLIB$clone$4()Ljava/lang/Object;")) {
                    return 17;
                }
                break;
            }
            case 1826985398: {
                if (string.equals("equals(Ljava/lang/Object;)Z")) {
                    return 0;
                }
                break;
            }
            case 1913648695: {
                if (string.equals("toString()Ljava/lang/String;")) {
                    return 1;
                }
                break;
            }
            case 1984935277: {
                if (string.equals("hashCode()I")) {
                    return 2;
                }
                break;
            }
        }
        return -1;
    }
    
    public int getIndex(final String s, final Class[] array) {
        Label_1103: {
            switch (s.hashCode()) {
                case -1776922004: {
                    if (!s.equals("toString")) {
                        break;
                    }
                    switch (array.length) {
                        case 0: {
                            return 1;
                        }
                        default: {
                            break Label_1103;
                        }
                    }
                    break;
                }
                case -1295482945: {
                    if (!s.equals("equals")) {
                        break;
                    }
                    switch (array.length) {
                        case 1: {
                            if (array[0].getName().equals("java.lang.Object")) {
                                return 0;
                            }
                            break Label_1103;
                        }
                        default: {
                            break Label_1103;
                        }
                    }
                    break;
                }
                case -1053468136: {
                    if (!s.equals("getCallbacks")) {
                        break;
                    }
                    switch (array.length) {
                        case 0: {
                            return 10;
                        }
                        default: {
                            break Label_1103;
                        }
                    }
                    break;
                }
                case -838595071: {
                    if (!s.equals("upload")) {
                        break;
                    }
                    switch (array.length) {
                        case 1: {
                            if (array[0].getName().equals("com.reape.design.pattern.proxy.cglib.JDKData")) {
                                return 8;
                            }
                            break Label_1103;
                        }
                        default: {
                            break Label_1103;
                        }
                    }
                    break;
                }
                case -124978609: {
                    if (!s.equals("CGLIB$equals$1")) {
                        break;
                    }
                    switch (array.length) {
                        case 1: {
                            if (array[0].getName().equals("java.lang.Object")) {
                                return 15;
                            }
                            break Label_1103;
                        }
                        default: {
                            break Label_1103;
                        }
                    }
                    break;
                }
                case -60403779: {
                    if (!s.equals("CGLIB$SET_STATIC_CALLBACKS")) {
                        break;
                    }
                    switch (array.length) {
                        case 1: {
                            if (array[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
                                return 13;
                            }
                            break Label_1103;
                        }
                        default: {
                            break Label_1103;
                        }
                    }
                    break;
                }
                case -29025555: {
                    if (!s.equals("CGLIB$hashCode$3")) {
                        break;
                    }
                    switch (array.length) {
                        case 0: {
                            return 18;
                        }
                        default: {
                            break Label_1103;
                        }
                    }
                    break;
                }
                case 85179481: {
                    if (!s.equals("CGLIB$SET_THREAD_CALLBACKS")) {
                        break;
                    }
                    switch (array.length) {
                        case 1: {
                            if (array[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
                                return 12;
                            }
                            break Label_1103;
                        }
                        default: {
                            break Label_1103;
                        }
                    }
                    break;
                }
                case 94756189: {
                    if (!s.equals("clone")) {
                        break;
                    }
                    switch (array.length) {
                        case 0: {
                            return 3;
                        }
                        default: {
                            break Label_1103;
                        }
                    }
                    break;
                }
                case 147696667: {
                    if (!s.equals("hashCode")) {
                        break;
                    }
                    switch (array.length) {
                        case 0: {
                            return 2;
                        }
                        default: {
                            break Label_1103;
                        }
                    }
                    break;
                }
                case 161998109: {
                    if (!s.equals("CGLIB$STATICHOOK1")) {
                        break;
                    }
                    switch (array.length) {
                        case 0: {
                            return 19;
                        }
                        default: {
                            break Label_1103;
                        }
                    }
                    break;
                }
                case 495524492: {
                    if (!s.equals("setCallbacks")) {
                        break;
                    }
                    switch (array.length) {
                        case 1: {
                            if (array[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
                                return 11;
                            }
                            break Label_1103;
                        }
                        default: {
                            break Label_1103;
                        }
                    }
                    break;
                }
                case 857604112: {
                    if (!s.equals("CGLIB$upload$0")) {
                        break;
                    }
                    switch (array.length) {
                        case 1: {
                            if (array[0].getName().equals("com.reape.design.pattern.proxy.cglib.JDKData")) {
                                return 14;
                            }
                            break Label_1103;
                        }
                        default: {
                            break Label_1103;
                        }
                    }
                    break;
                }
                case 1154623345: {
                    if (!s.equals("CGLIB$findMethodProxy")) {
                        break;
                    }
                    switch (array.length) {
                        case 1: {
                            if (array[0].getName().equals("net.sf.cglib.core.Signature")) {
                                return 20;
                            }
                            break Label_1103;
                        }
                        default: {
                            break Label_1103;
                        }
                    }
                    break;
                }
                case 1543336189: {
                    if (!s.equals("CGLIB$toString$2")) {
                        break;
                    }
                    switch (array.length) {
                        case 0: {
                            return 16;
                        }
                        default: {
                            break Label_1103;
                        }
                    }
                    break;
                }
                case 1811874389: {
                    if (!s.equals("newInstance")) {
                        break;
                    }
                    switch (array.length) {
                        case 1: {
                            final String name = array[0].getName();
                            switch (name.hashCode()) {
                                case -845341380: {
                                    if (name.equals("net.sf.cglib.proxy.Callback")) {
                                        return 6;
                                    }
                                    break;
                                }
                                case 1730110032: {
                                    if (name.equals("[Lnet.sf.cglib.proxy.Callback;")) {
                                        return 4;
                                    }
                                    break;
                                }
                            }
                            break Label_1103;
                        }
                        case 3: {
                            if (array[0].getName().equals("[Ljava.lang.Class;") && array[1].getName().equals("[Ljava.lang.Object;") && array[2].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
                                return 5;
                            }
                            break Label_1103;
                        }
                        default: {
                            break Label_1103;
                        }
                    }
                    break;
                }
                case 1817099975: {
                    if (!s.equals("setCallback")) {
                        break;
                    }
                    switch (array.length) {
                        case 2: {
                            if (array[0].getName().equals("int") && array[1].getName().equals("net.sf.cglib.proxy.Callback")) {
                                return 7;
                            }
                            break Label_1103;
                        }
                        default: {
                            break Label_1103;
                        }
                    }
                    break;
                }
                case 1905679803: {
                    if (!s.equals("getCallback")) {
                        break;
                    }
                    switch (array.length) {
                        case 1: {
                            if (array[0].getName().equals("int")) {
                                return 9;
                            }
                            break Label_1103;
                        }
                        default: {
                            break Label_1103;
                        }
                    }
                    break;
                }
                case 1951977610: {
                    if (!s.equals("CGLIB$clone$4")) {
                        break;
                    }
                    switch (array.length) {
                        case 0: {
                            return 17;
                        }
                        default: {
                            break Label_1103;
                        }
                    }
                    break;
                }
            }
        }
        return -1;
    }
    
    public int getIndex(final Class[] array) {
        switch (array.length) {
            case 0: {
                return 0;
            }
            default: {
                return -1;
            }
        }
    }
    
    public Object invoke(final int n, final Object o, final Object[] array) throws InvocationTargetException {
        final JDKFTPService$$EnhancerByCGLIB$$5a7831ef jdkftpService$$EnhancerByCGLIB$$5a7831ef = (JDKFTPService$$EnhancerByCGLIB$$5a7831ef)o;
        try {
            switch (n) {
                case 0: {
                    return new Boolean(jdkftpService$$EnhancerByCGLIB$$5a7831ef.equals(array[0]));
                }
                case 1: {
                    return jdkftpService$$EnhancerByCGLIB$$5a7831ef.toString();
                }
                case 2: {
                    return new Integer(jdkftpService$$EnhancerByCGLIB$$5a7831ef.hashCode());
                }
                case 3: {
                    return jdkftpService$$EnhancerByCGLIB$$5a7831ef.clone();
                }
                case 4: {
                    return jdkftpService$$EnhancerByCGLIB$$5a7831ef.newInstance((Callback[])array[0]);
                }
                case 5: {
                    return jdkftpService$$EnhancerByCGLIB$$5a7831ef.newInstance((Class[])array[0], (Object[])array[1], (Callback[])array[2]);
                }
                case 6: {
                    return jdkftpService$$EnhancerByCGLIB$$5a7831ef.newInstance((Callback)array[0]);
                }
                case 7: {
                    jdkftpService$$EnhancerByCGLIB$$5a7831ef.setCallback(((Number)array[0]).intValue(), (Callback)array[1]);
                    return null;
                }
                case 8: {
                    jdkftpService$$EnhancerByCGLIB$$5a7831ef.upload((JDKData)array[0]);
                    return null;
                }
                case 9: {
                    return jdkftpService$$EnhancerByCGLIB$$5a7831ef.getCallback(((Number)array[0]).intValue());
                }
                case 10: {
                    return jdkftpService$$EnhancerByCGLIB$$5a7831ef.getCallbacks();
                }
                case 11: {
                    jdkftpService$$EnhancerByCGLIB$$5a7831ef.setCallbacks((Callback[])array[0]);
                    return null;
                }
                case 12: {
                    JDKFTPService$$EnhancerByCGLIB$$5a7831ef.CGLIB$SET_THREAD_CALLBACKS((Callback[])array[0]);
                    return null;
                }
                case 13: {
                    JDKFTPService$$EnhancerByCGLIB$$5a7831ef.CGLIB$SET_STATIC_CALLBACKS((Callback[])array[0]);
                    return null;
                }
                case 14: {
                    jdkftpService$$EnhancerByCGLIB$$5a7831ef.CGLIB$upload$0((JDKData)array[0]);
                    return null;
                }
                case 15: {
                    return new Boolean(jdkftpService$$EnhancerByCGLIB$$5a7831ef.CGLIB$equals$1(array[0]));
                }
                case 16: {
                    return jdkftpService$$EnhancerByCGLIB$$5a7831ef.CGLIB$toString$2();
                }
                case 17: {
                    return jdkftpService$$EnhancerByCGLIB$$5a7831ef.CGLIB$clone$4();
                }
                case 18: {
                    return new Integer(jdkftpService$$EnhancerByCGLIB$$5a7831ef.CGLIB$hashCode$3());
                }
                case 19: {
                    JDKFTPService$$EnhancerByCGLIB$$5a7831ef.CGLIB$STATICHOOK1();
                    return null;
                }
                case 20: {
                    return JDKFTPService$$EnhancerByCGLIB$$5a7831ef.CGLIB$findMethodProxy((Signature)array[0]);
                }
            }
        }
        catch (Throwable t) {
            throw new InvocationTargetException(t);
        }
        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }
    
    public Object newInstance(final int n, final Object[] array) throws InvocationTargetException {
        try {
            switch (n) {
                case 0: {
                    return new JDKFTPService$$EnhancerByCGLIB$$5a7831ef();
                }
            }
        }
        catch (Throwable t) {
            throw new InvocationTargetException(t);
        }
        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }
    
    public int getMaxIndex() {
        return 20;
    }
}

// 裏面使用 extends FastClass
// 子類重寫父類的方法
// 父類方法不能是final

複製代碼

CGLib 和 JDK 動態代理對比

  1. JDK 動態代理是實現了被代理對象的接口,CGLib 是繼承了被代理對象。
  2. JDK 和 CGLib 都是在運行期生成字節碼,JDK 是直接寫 Class 字節碼,CGLib 使用 ASM 框架寫 Class 字節碼,Cglib 代理實現更復雜,生成代理類比 JDK 效率低。
  3. JDK 調用代理方法,是經過反射機制調用,CGLib 是經過 FastClass 機制直接調用方法, CGLib 執行效率更高。

靜態代理和動態的本質區別

  1. 靜態代理只能經過手動完成代理操做,若是被代理類增長新的方法,代理類須要同步 新增,違背開閉原則。
  2. 動態代理採用在運行時動態生成代碼的方式,取消了對被代理類的擴展限制,遵循開 閉原則。
  3. 若動態代理要對目標類的加強邏輯擴展,結合策略模式,只須要新增策略類即可完成, 無需修改代理類的代碼。 代理模式的優缺點 使用代理模式具備如下幾個優勢:
  • 代理模式能將代理對象與真實被調用的目標對象分離。框架

  • 必定程度上下降了系統的耦合度,擴展性好。jvm

  • 能夠起到保護目標對象的做用。ide

  • 能夠對目標對象的功能加強。工具

固然,代理模式也是有缺點的:測試

  1. 代理模式會形成系統設計中類的數量增長。
  2. 在客戶端和目標對象增長一個代理對象,會形成請求處理速度變慢。
  3. 增長了系統的複雜度。

執行速度

ASM > javassist > 手寫的(java -> class -> 加載)

相關文章
相關標籤/搜索