代理模式

定义

代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。符合开闭原则。代理模式属于结构型 模式,有静态代理和动态代理。

静态代理

需求:现在我们需要根据类型来分别把数据上传到不同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 {@Overridepublic 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;}@Overridepublic 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 {@Overridepublic 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);}@Overridepublic 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");elseSystem.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代码如下:


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);//2、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();//3、把生成的.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();//4、编译生成的.class 文件加载到 JVM 中来Class<Object> proxyClass = (Class<Object>) classLoader.findClass("$Proxy0");Constructor<Object> c = proxyClass.getConstructor(MyInvocationHandler.class);
//            f.delete();//5、返回字节码重组以后的新的代理对象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.");}@Overridepublic 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.jarpublic 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 {@Overridepublic 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();}@Overridepublic 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");elseSystem.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. 若动态代理要对目标类的增强逻辑扩展,结合策略模式,只需要新增策略类便可完成, 无需修改代理类的代码。 代理模式的优缺点 使用代理模式具有以下几个优点:
  • 代理模式能将代理对象与真实被调用的目标对象分离。

  • 一定程度上降低了系统的耦合度,扩展性好。

  • 可以起到保护目标对象的作用。

  • 可以对目标对象的功能增强。

当然,代理模式也是有缺点的:

  1. 代理模式会造成系统设计中类的数量增加。
  2. 在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢。
  3. 增加了系统的复杂度。

执行速度

ASM > javassist > 手写的(java -> class -> 加载)

转载于:https://juejin.im/post/5ce20b9ae51d4510843bb48e

RE|GoF23种设计模式-动态代理相关推荐

  1. GOF23种设计模式在Java中的应用(part 2)

    本文接续part1:GOF23种设计模式在Java中的应用(part 1) 结构型模式 结构型模式: – 核心作用:是从程序的结构上实现松耦合,从而可以扩大整体的类结 构,用来解决更大的问题. – 分 ...

  2. GOF23种设计模式你知道是什么吗?都有什么作用?

    ​一.GOF简介       GOF是设计模式的经典名著Design Patterns: Elements of Reusable Object-Oriented Software(中译本名为< ...

  3. 【Java】Java与GoF-23种设计模式

    文章目录 设计模式概述 GoF-23种设计模式 设计模式的分类 设计模式的原则 设计模式在JDK的部分体现 Singleton Factory Abstract factory Adapter Com ...

  4. Java二十三种设计模式 之代理(proxy)

    Java二十三种设计模式 之代理(proxy) 今天我们学习一下静态代理和动态代理 我们来看代码(写一个坦克运行了多少时间): 第一种方法: public calss Tank implements ...

  5. GOF23种设计模式在Java中的应用(part 3)

    本文接续:GOF23种设计模式在Java中的应用(part 2) 行为型模式 行为型模式关注系统中对象之间的相互交互.,研究系统在运行时对象之间的相互通信和协作,进一步明确对象的职责,共有11种模式. ...

  6. GOF23种设计模式在Java中的应用(part 1)

    第二部分:GOF23种设计模式在Java中的应用(part 2) 一.GOF来源及简介 1.1 GOF23种设计模式简介 <Design Patterns: Elements of Reusab ...

  7. 【设计模式系列24】GoF23种设计模式总结及软件设计7大原则

    设计模式总结及软件设计七大原则 设计模式系列总览 前言 软件设计7大原则 开闭原则(Open-Closed Principle,OCP) 里氏替换原则(Liskov Substitution Prin ...

  8. 23种设计模式7_代理模式之一静态代理

    23种设计模式7_代理模式之一静态代理 1 基本介绍 代理模式:为其他对象提供一种代理以控制对这个对象的访问 代理模式也叫委托模式,它是一项基本设计技巧.许多其他的模式,如状态模式.策略模式.访问者模 ...

  9. 研磨23种大话设计模式------动态代理模式 + 小结静态代理模式

    大家好,我是一位在java学习圈中不愿意透露姓名并苟且偷生的小学员,如果文章有错误之处,还望海涵,欢迎多多指正 如果你从本文 get 到有用的干货知识,请帮忙点个赞呗,据说点赞的都拿到了offer 在 ...

最新文章

  1. ng1和ng2的部分对比----angular2系列(四)
  2. 大牛是怎么思考设计SQL优化方案的?
  3. Python元组tuple(不可变)
  4. 使用Arduino开发ESP32:wifi基本功能使用
  5. UVA 11584—— Partitioning by Palindromes
  6. 获取当前的系统环境(python)
  7. 【感悟】本书书名无法描述本书内容(二)
  8. 【Hive】Hive的数据类型
  9. POJ 2728 Desert King(最优比率生成树)
  10. redis 备份与恢复
  11. java win10_java下载64位win10-javawin10 64位下载8.0.1210.13官方版-西西软件下载
  12. scratch算立方根
  13. 在docker下进行ETH并行训练和在本机下进行ETH并行训练
  14. 拉萨java培训_西藏拉萨PHP培训地址在哪学费多少
  15. 爬虫君子协议-robots.txt协议
  16. ❤️学懂C语言文件操作读这篇就够了(万字总结,附习题)❤️
  17. 阿里域名+腾讯云服务器组合部署网站
  18. android安卓实现圆形头像效果(使用第三方开源库)
  19. 三星“太子”李在镕加入三星电子董事会
  20. 关键词过滤(脏字过滤)Trie Tree(Hash)和FastCheck两种过滤方式java版本

热门文章

  1. 学好python薪水有多少笔画_Python学到什么程度可以面试工作?
  2. insert 语句_CTF从入门到提升(七)insert 等数据表相关操作注入及例题分享
  3. python爬虫实战测评_Python 爬虫实战入门(上)
  4. tms570 can 接收大量数据_CAN通讯系列--AUTOSAR架构的CAN Interface7
  5. 俄罗斯方块android论文,基于Android的俄罗斯方块游戏设计与实现(论文+任务书+答辩PPT+设计源码)...
  6. axure小程序模板_微信小程序模板案例收集
  7. java1.6 linux_linux java1.6 安装
  8. 使用intellij idea打开以前用maven的包
  9. 声明对象_计算机各语言数据类型及对象声明之区别
  10. 百练OJ:2742:统计字符数