RE|GoF23种设计模式-动态代理
代理模式
定义
代理(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);
}复制代码
动态代理
动态代理有以下特点:
- 代理对象,不需要实现接口
- 代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)
- 动态代理也叫做: 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 生成对象的步骤如下:
- 拿到被代理对象的引用,并且获取到它的所有的接口,反射获取。
- JDK Proxy 类重新生成一个新的类、同时新的类要实现被代理类所有实现的所有的接口。
- 动态生成 Java 代码,把新加的业务逻辑方法由一定的逻辑代码去调用(在代码中体现)。
- 编译新生成的 Java 代码.class。
- 再重新加载到 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 动态代理对比
- JDK 动态代理是实现了被代理对象的接口,CGLib 是继承了被代理对象。
- JDK 和 CGLib 都是在运行期生成字节码,JDK 是直接写 Class 字节码,CGLib 使用 ASM 框架写 Class 字节码,Cglib 代理实现更复杂,生成代理类比 JDK 效率低。
- JDK 调用代理方法,是通过反射机制调用,CGLib 是通过 FastClass 机制直接调用方法, CGLib 执行效率更高。
静态代理和动态的本质区别
- 静态代理只能通过手动完成代理操作,如果被代理类增加新的方法,代理类需要同步 新增,违背开闭原则。
- 动态代理采用在运行时动态生成代码的方式,取消了对被代理类的扩展限制,遵循开 闭原则。
- 若动态代理要对目标类的增强逻辑扩展,结合策略模式,只需要新增策略类便可完成, 无需修改代理类的代码。 代理模式的优缺点 使用代理模式具有以下几个优点:
代理模式能将代理对象与真实被调用的目标对象分离。
一定程度上降低了系统的耦合度,扩展性好。
可以起到保护目标对象的作用。
可以对目标对象的功能增强。
当然,代理模式也是有缺点的:
- 代理模式会造成系统设计中类的数量增加。
- 在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢。
- 增加了系统的复杂度。
执行速度
ASM > javassist > 手写的(java -> class -> 加载)
转载于:https://juejin.im/post/5ce20b9ae51d4510843bb48e
RE|GoF23种设计模式-动态代理相关推荐
- GOF23种设计模式在Java中的应用(part 2)
本文接续part1:GOF23种设计模式在Java中的应用(part 1) 结构型模式 结构型模式: – 核心作用:是从程序的结构上实现松耦合,从而可以扩大整体的类结 构,用来解决更大的问题. – 分 ...
- GOF23种设计模式你知道是什么吗?都有什么作用?
一.GOF简介 GOF是设计模式的经典名著Design Patterns: Elements of Reusable Object-Oriented Software(中译本名为< ...
- 【Java】Java与GoF-23种设计模式
文章目录 设计模式概述 GoF-23种设计模式 设计模式的分类 设计模式的原则 设计模式在JDK的部分体现 Singleton Factory Abstract factory Adapter Com ...
- Java二十三种设计模式 之代理(proxy)
Java二十三种设计模式 之代理(proxy) 今天我们学习一下静态代理和动态代理 我们来看代码(写一个坦克运行了多少时间): 第一种方法: public calss Tank implements ...
- GOF23种设计模式在Java中的应用(part 3)
本文接续:GOF23种设计模式在Java中的应用(part 2) 行为型模式 行为型模式关注系统中对象之间的相互交互.,研究系统在运行时对象之间的相互通信和协作,进一步明确对象的职责,共有11种模式. ...
- GOF23种设计模式在Java中的应用(part 1)
第二部分:GOF23种设计模式在Java中的应用(part 2) 一.GOF来源及简介 1.1 GOF23种设计模式简介 <Design Patterns: Elements of Reusab ...
- 【设计模式系列24】GoF23种设计模式总结及软件设计7大原则
设计模式总结及软件设计七大原则 设计模式系列总览 前言 软件设计7大原则 开闭原则(Open-Closed Principle,OCP) 里氏替换原则(Liskov Substitution Prin ...
- 23种设计模式7_代理模式之一静态代理
23种设计模式7_代理模式之一静态代理 1 基本介绍 代理模式:为其他对象提供一种代理以控制对这个对象的访问 代理模式也叫委托模式,它是一项基本设计技巧.许多其他的模式,如状态模式.策略模式.访问者模 ...
- 研磨23种大话设计模式------动态代理模式 + 小结静态代理模式
大家好,我是一位在java学习圈中不愿意透露姓名并苟且偷生的小学员,如果文章有错误之处,还望海涵,欢迎多多指正 如果你从本文 get 到有用的干货知识,请帮忙点个赞呗,据说点赞的都拿到了offer 在 ...
最新文章
- ng1和ng2的部分对比----angular2系列(四)
- 大牛是怎么思考设计SQL优化方案的?
- Python元组tuple(不可变)
- 使用Arduino开发ESP32:wifi基本功能使用
- UVA 11584—— Partitioning by Palindromes
- 获取当前的系统环境(python)
- 【感悟】本书书名无法描述本书内容(二)
- 【Hive】Hive的数据类型
- POJ 2728 Desert King(最优比率生成树)
- redis 备份与恢复
- java win10_java下载64位win10-javawin10 64位下载8.0.1210.13官方版-西西软件下载
- scratch算立方根
- 在docker下进行ETH并行训练和在本机下进行ETH并行训练
- 拉萨java培训_西藏拉萨PHP培训地址在哪学费多少
- 爬虫君子协议-robots.txt协议
- ❤️学懂C语言文件操作读这篇就够了(万字总结,附习题)❤️
- 阿里域名+腾讯云服务器组合部署网站
- android安卓实现圆形头像效果(使用第三方开源库)
- 三星“太子”李在镕加入三星电子董事会
- 关键词过滤(脏字过滤)Trie Tree(Hash)和FastCheck两种过滤方式java版本
热门文章
- 学好python薪水有多少笔画_Python学到什么程度可以面试工作?
- insert 语句_CTF从入门到提升(七)insert 等数据表相关操作注入及例题分享
- python爬虫实战测评_Python 爬虫实战入门(上)
- tms570 can 接收大量数据_CAN通讯系列--AUTOSAR架构的CAN Interface7
- 俄罗斯方块android论文,基于Android的俄罗斯方块游戏设计与实现(论文+任务书+答辩PPT+设计源码)...
- axure小程序模板_微信小程序模板案例收集
- java1.6 linux_linux java1.6 安装
- 使用intellij idea打开以前用maven的包
- 声明对象_计算机各语言数据类型及对象声明之区别
- 百练OJ:2742:统计字符数