Java设计模式——代理模式
Posted 楼子湾
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java设计模式——代理模式相关的知识,希望对你有一定的参考价值。
一.定义
代理模式(Proxy Pattern): 提供了间接对目标对象的访问方式---即通过代理对象访问目标对象, 代理对象就类似中介
代理模式分类:静态代理和动态代理,动态代理又分为jdk动态代理和cglib动态代理
二.静态代理
被代理对象和代理对象需要实现相同的接口或者继承相同父类同时代理对象中添加对代理对象接口或者抽象类的引用,故要定义一个借口或者抽象类
示例:
1 // 接口: 代理对象和被代理对象的共同接口 2 public interface IStar { 3 public void sing(); 4 } 5 6 // 具体的被代理对象:谢霆锋唱歌 7 public class XTFIStar implements IStar { 8 9 @Override 10 public void sing() { 11 System.out.println("谢霆锋唱歌"); 12 } 13 } 14 15 /** 16 * 代理对象: 1.和被代理对象实现相同的接口 17 * 2.持有对被代理对象的引用 18 */ 19 public class ProxyManager implements IStar { 20 21 private IStar iStar; 22 public ProxyManager(IStar iStar) { 23 this.iStar = iStar; 24 } 25 26 @Override 27 public void sing() { 28 System.out.println("唱歌前准备"); 29 iStar.sing(); 30 System.out.println("唱歌后分钱"); 31 } 32 } 33 34 // 测试: 35 ProxyManager proxyManager = new ProxyManager(new XTFIStar()); 36 proxyManager.sing();
测试结果:通过经纪人找刘德华唱歌
静态代理:
优点:可以在不修改目标对象功能的前提下,对目标功能进行扩展
缺点:因为代理对象和目标对象需要实现相同的接口,所以会有很多代理类,类太多。同时,接口一旦增加方法,目标对象与代理对象都需要维护。
三.动态代理
动态代理的主要特点是能够在程序运行时JVM才为被代理对象生成代理对象
动态代理分为:JDK动态代理和cglib动态代理
1.JDK动态代理是一种接口代理,JDK中生成的代理对象的代理类是Proxy,所在包是java.lang.reflect
使用三个包就可以完成JDK动态代理。
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;
1)实现InvocationHandle接口;2)匿名内部实现接口通过 new InvocationHandle({重写invoke方法})
1 // 被代理对象实现的接口 2 public interface IDog { 3 void run(); 4 void eat(); 5 } 6 7 // 被代理的具体对象 8 public class BingliDog implements IDog { 9 @Override 10 public void run() { 11 System.out.println("宾利狗狗在奔跑"); 12 } 13 14 @Override 15 public void eat() { 16 System.out.println("宾利在吃狗粮"); 17 } 18 } 19 20 // 用于增强的方法 21 public class DogUtils { 22 public static void method1(){ 23 System.out.println("大摇大摆的来了"); 24 } 25 26 public static void method2(){ 27 System.out.println("大摇大摆的走了"); 28 } 29 } 30 // 执行器 31 public class MyInvocationHandle implements InvocationHandler { 32 private Object target; 33 34 public void setTarget(Object target) { 35 this.target = target; 36 } 37 38 @Override 39 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 40 DogUtils.method1(); 41 Object invoke = method.invoke(target, args); 42 DogUtils.method2(); 43 return null; 44 } 45 } 46 47 // 代理对象工厂 48 public class MyProxyFactory { 49 50 public static Object getProxy(Object target){ 51 MyInvocationHandle myInvocationHandle = new MyInvocationHandle(); 52 myInvocationHandle.setTarget(target); 53 Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), myInvocationHandle); 54 return proxy; 55 } 56 } 57 58 // 测试: 59 IDog proxy = (IDog) MyProxyFactory.getProxy(new BingliDog()); 60 proxy.run(); 61 proxy.eat();
测试结果:涉及Proxy类,Method, InvocationHandle,被代理的对象必须实现接口
总结: 代理对象不需要实现接口,被代理的对象一定要实现接口,否则不能实现动态代理
2.cglib代理
上面的静态代理和动态代理都要求目标实现一个接口,然后并不是任何一个对象都实现一个接口。
这时就可以继承目标类以目标类子类的方式实现代理,这种方式就叫cglib代理,也叫做子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展。
使用JDK的动态代理有一个限制,目标类必须实现一个或者多个接口,若想代理没有实现接口的类,就使用cglib代理
cglib使用的是第三方jar包:在spring-core中已经有对这两个包的引用,故不用额外对其引用
cglib包的底层是通过使用字节码处理框架ASM来生产新的java类
与jdk动态代理的区别:第一点可以省略接口;第二点代理工程使用的是 org.springframework.cglib.proxy.enhancer来帮助我们生产对象
1 // 没有实现接口的类 2 public class HelloService { 3 public HelloService() { 4 System.out.println("HelloService的构造"); 5 } 6 7 final public String sayOthers(String name){ 8 System.out.println("HelloService:sayOthers>>"+name); 9 return null; 10 } 11 12 public void sayHello(){ 13 System.out.println("HelloService:sayHello"); 14 } 15 } 16 17 // 方法拦截器 18 public class MyMethodInterceptor implements MethodInterceptor { 19 /** 20 * 21 * @param sub:cglib生产的代理对象 22 * @param method: 被代理对象的方法 23 * @param args: 方法入参 24 * @param methodProxy: 代理方法 25 * @return 26 * @throws Throwable 27 */ 28 @Override 29 public Object intercept(Object sub, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { 30 System.out.println("执行方法前doSomething..."); 31 Object invoke = methodProxy.invokeSuper(sub, args); 32 System.out.println("执行方法后doSomething..."); 33 return invoke; 34 } 35 } 36 // 工厂类 37 public class CglibFactory { 38 public static <T> T getProxy(Class<T> clazz, MethodInterceptor myMethodInterceptor){ 39 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"C:\\\\Users\\\\wxf\\\\Desktop"); 40 Enhancer enhancer = new Enhancer(); 41 enhancer.setSuperclass(clazz); 42 enhancer.setCallback(myMethodInterceptor); 43 return (T) enhancer.create(); 44 } 45 } 46 47 测试: 48 MethodInterceptor methodInterceptor = new MyMethodInterceptor(); 49 HelloService proxy = CglibFactory.getProxy(HelloService.class, methodInterceptor); 50 proxy.sayHello(); 51 proxy.sayOthers("proxy");
结果:sayOthers 方法被final修饰的不能被cglib代理
生产的代理class文件
第二个文件反编译结果如下:
1 package com.design.proxy.cglib; 2 3 import java.lang.reflect.Method; 4 import org.springframework.cglib.core.ReflectUtils; 5 import org.springframework.cglib.core.Signature; 6 import org.springframework.cglib.proxy.Callback; 7 import org.springframework.cglib.proxy.Factory; 8 import org.springframework.cglib.proxy.MethodInterceptor; 9 import org.springframework.cglib.proxy.MethodProxy; 10 11 public class HelloService$$EnhancerByCGLIB$$5cb8654c extends HelloService implements Factory { 12 private boolean CGLIB$BOUND; 13 14 public static Object CGLIB$FACTORY_DATA; 15 16 private static final ThreadLocal CGLIB$THREAD_CALLBACKS; 17 18 private static final Callback[] CGLIB$STATIC_CALLBACKS; 19 20 private MethodInterceptor CGLIB$CALLBACK_0; 21 22 private static Object CGLIB$CALLBACK_FILTER; 23 24 private static final Method CGLIB$sayHello$0$Method; 25 26 private static final MethodProxy CGLIB$sayHello$0$Proxy; 27 28 private static final Object[] CGLIB$emptyArgs; 29 30 private static final Method CGLIB$equals$1$Method; 31 32 private static final MethodProxy CGLIB$equals$1$Proxy; 33 34 private static final Method CGLIB$toString$2$Method; 35 36 private static final MethodProxy CGLIB$toString$2$Proxy; 37 38 private static final Method CGLIB$hashCode$3$Method; 39 40 private static final MethodProxy CGLIB$hashCode$3$Proxy; 41 42 private static final Method CGLIB$clone$4$Method; 43 44 private static final MethodProxy CGLIB$clone$4$Proxy; 45 46 static void CGLIB$STATICHOOK1() { 47 CGLIB$THREAD_CALLBACKS = new ThreadLocal(); 48 CGLIB$emptyArgs = new Object[0]; 49 Class<?> clazz1 = Class.forName("com.design.proxy.cglib.HelloService$$EnhancerByCGLIB$$5cb8654c"); 50 Class<?> clazz2; 51 CGLIB$equals$1$Method = ReflectUtils.findMethods(new String[] { "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;" }, (clazz2 = Class.forName("java.lang.Object")).getDeclaredMethods())[0]; 52 CGLIB$equals$1$Proxy = MethodProxy.create(clazz2, clazz1, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1"); 53 CGLIB$toString$2$Method = ReflectUtils.findMethods(new String[] { "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;" }, (clazz2 = Class.forName("java.lang.Object")).getDeclaredMethods())[1]; 54 CGLIB$toString$2$Proxy = MethodProxy.create(clazz2, clazz1, "()Ljava/lang/String;", "toString", "CGLIB$toString$2"); 55 CGLIB$hashCode$3$Method = ReflectUtils.findMethods(new String[] { "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;" }, (clazz2 = Class.forName("java.lang.Object")).getDeclaredMethods())[2]; 56 CGLIB$hashCode$3$Proxy = MethodProxy.create(clazz2, clazz1, "()I", "hashCode", "CGLIB$hashCode$3"); 57 CGLIB$clone$4$Method = ReflectUtils.findMethods(new String[] { "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;" }, (clazz2 = Class.forName("java.lang.Object")).getDeclaredMethods())[3]; 58 CGLIB$clone$4$Proxy = MethodProxy.create(clazz2, clazz1, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4"); 59 ReflectUtils.findMethods(new String[] { "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;" }, (clazz2 = Class.forName("java.lang.Object")).getDeclaredMethods()); 60 CGLIB$sayHello$0$Method = ReflectUtils.findMethods(new String[] { "sayHello", "()V" }, (clazz2 = Class.forName("com.design.proxy.cglib.HelloService")).getDeclaredMethods())[0]; 61 CGLIB$sayHello$0$Proxy = MethodProxy.create(clazz2, clazz1, "()V", "sayHello", "CGLIB$sayHello$0"); 62 ReflectUtils.findMethods(new String[] { "sayHello", "()V" }, (clazz2 = Class.forName("com.design.proxy.cglib.HelloService")).getDeclaredMethods()); 63 } 64 65 final void CGLIB$sayHello$0() { 66 super.sayHello(); 67 } 68 69 public final void sayHello() { 70 if (this.CGLIB$CALLBACK_0 == null) 71 CGLIB$BIND_CALLBACKS(this); 72 if (this.CGLIB$CALLBACK_0 != null) 73 return; 74 super.sayHello(); 75 } 76 77 final boolean CGLIB$equals$1(Object paramObject) { 78 return super.equals(paramObject); 79 } 80 81 public final boolean equals(Object paramObject) { 82 if (this.CGLIB$CALLBACK_0 == null) 83 CGLIB$BIND_CALLBACKS(this); 84 if (this.CGLIB$CALLBACK_0 != null) { 85 this.CGLIB$CALLBACK_0.intercept(this, CGLIB$equals$1$Method, new Object[] { paramObject }, CGLIB$equals$1$Proxy); 86 return (this.CGLIB$CALLBACK_0.intercept(this, CGLIB$equals$1$Method, new Object[] { paramObject }, CGLIB$equals$1$Proxy) == null) ? false : ((Boolean)this.CGLIB$CALLBACK_0.intercept(this, CGLIB$equals$1$Method, new Object[] { paramObject }, CGLIB$equals$1$Proxy)).booleanValue(); 87 } 88 return super.equals(paramObject); 89 } 90 91 final String CGLIB$toString$2() { 92 return super.toString(); 93 } 94 95 public final String toString() { 96 if (this.CGLIB$CALLBACK_0 == null) 97 CGLIB$BIND_CALLBACKS(this); 98 return (this.CGLIB$CALLBACK_0 != null) ? (String)this.CGLIB$CALLBACK_0.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy) : super.toString(); 99 } 100 101 final int CGLIB$hashCode$3() { 102 return super.hashCode(); 103 } 104 105 public final int hashCode() { 106 if (this.CGLIB$CALLBACK_0 == null) 107 CGLIB$BIND_CALLBACKS(this); 108 if (this.CGLIB$CALLBACK_0 != null) { 109 this.CGLIB$CALLBACK_0.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy); 110 return (this.CGLIB$CALLBACK_0.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy) == null) ? 0 : ((Number)this.CGLIB$CALLBACK_0.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy)).intValue(); 111 } 112 return super.hashCode(); 113 } 114 115 final Object CGLIB$clone$4() throws CloneNotSupportedException { 116 return super.clone(); 117 } 118 119 protected final Object clone() throws CloneNotSupportedException { 120 if (this.CGLIB$CALLBACK_0 == null) 121 CGLIB$BIND_CALLBACKS(this); 122 return (this.CGLIB$CALLBACK_0 != null) ? this.CGLIB$CALLBACK_0.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy) : super.clone(); 123 } 124 125 public static MethodProxy CGLIB$findMethodProxy(Signature paramSignature) { 126 // Byte code: 127 // 0: aload_0 128 // 1: invokevirtual toString : ()Ljava/lang/String; 129 // 4: dup 130 // 5: invokevirtual hashCode : ()I 131 // 8: lookupswitch default -> 120, -508378822 -> 60, 1535311470 -> 72, 1826985398 -> 84, 1913648695 -> 96, 1984935277 -> 108 132 // 60: ldc \'clone()Ljava/lang/Object;\' 133 // 62: invokevirtual equals : (Ljava/lang/Object;)Z 134 // 65: ifeq -> 121 135 // 68: getstatic com/design/proxy/cglib/HelloService$$EnhancerByCGLIB$$5cb8654c.CGLIB$clone$4$Proxy : Lorg/springframework/cglib/proxy/MethodProxy; 136 // 71: areturn 137 // 72: ldc \'sayHello()V\' 138 // 74: invokevirtual equals : (Ljava/lang/Object;)Z 139 // 77: ifeq -> 121 140 // 80: getstatic com/design/proxy/cglib/HelloService$$EnhancerByCGLIB$$5cb8654c.CGLIB$sayHello$0$Proxy : Lorg/springframework/cglib/proxy/MethodProxy; 141 // 83: areturn 142 // 84: ldc \'equals(Ljava/lang/Object;)Z\' 143 // 86: invokevirtual equals : (Ljava/lang/Object;)Z 144 // 89: ifeq -> 121 145 // 92: getstatic com/design/proxy/cglib/HelloService$$EnhancerByCGLIB$$5cb8654c.CGLIB$equals$1$Proxy : Lorg/springframework/cglib/proxy/MethodProxy; 146 // 95: areturn 147 // 96: ldc \'toString()Ljava/lang/String;\' 148 // 98: invokevirtual equals : (Ljava/lang/Object;)Z 149 // 101: ifeq -> 121 150 // 104: getstatic com/design/proxy/cglib/HelloService$$EnhancerByCGLIB$$5cb8654c.CGLIB$toString$2$Proxy : Lorg/springframework/cglib/proxy/MethodProxy; 151 // 107: areturn 152 // 108: ldc \'hashCode()I\' 153 // 110: invokevirtual equals : (Ljava/lang/Object;)Z 154 // 113: ifeq -> 121 155 // 116: getstatic com/design/proxy/cglib/HelloService$$EnhancerByCGLIB$$5cb8654c.CGLIB$hashCode$3$Proxy : Lorg/springframework/cglib/proxy/MethodProxy; 156 // 119: areturn 157 // 120: pop 158 // 121: aconst_null 159 // 122: areturn 160 } 161 162 public HelloService$$EnhancerByCGLIB$$5cb8654c() { 163 CGLIB$BIND_CALLBACKS(this); 164 } 165 166 public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] paramArrayOfCallback) { 167 CGLIB$THREAD_CALLBACKS.set(paramArrayOfCallback); 168 } 169 170 public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] paramArrayOfCallback) { 171 CGLIB$STATIC_CALLBACKS = paramArrayOfCallback; 172 } 173 174 private static final void CGLIB$BIND_CALLBACKS(Object paramObject) { 175 HelloService$$EnhancerByCGLIB$$5cb8654c helloService$$EnhancerByCGLIB$$5cb8654c = (HelloService$$EnhancerByCGLIB$$5cb8654c)paramObject; 176 if (!helloService$$EnhancerByCGLIB$$5cb8654c.CGLIB$BOUND) { 177 helloService$$EnhancerByCGLIB$$5cb8654c.CGLIB$BOUND = true; 178 if (CGLIB$THREAD_CALLBACKS.get() == null) { 179 CGLIB$THREAD_CALLBACKS.get(); 180 if (CGLIB$STATIC_CALLBACKS == null) 181 return; 182 } 183 helloService$$EnhancerByCGLIB$$5cb8654c.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])CGLIB$THREAD_CALLBACKS.get())[0]; 184 } 185 } 186 187 public Object newInstance(Callback[] paramArrayOfCallback) { 188 CGLIB$SET_THREAD_CALLBACKS(paramArrayOfCallback); 189 CGLIB$SET_THREAD_CALLBACKS(null); 190 return new HelloService$$EnhancerByCGLIB$$5cb8654c(); 191 } 192 193 public Object newInstance(Callback paramCallback) { 194 CGLIB$SET_THREAD_CALLBACKS(new Callback[] { paramCallback }); 195 CGLIB$SET_THREAD_CALLBACKS(null); 196 return new HelloService$$EnhancerByCGLIB$$5cb8654c(); 197 } 198 199 public Object newInstance(Class[] paramArrayOfClass, Object[] paramArrayOfObject, Callback[] paramArrayOfCallback) { 200 // Byte code: 201 // 0: aload_3 202 // 1: invokestatic CGLIB$SET_THREAD_CALLBACKS : ([Lorg/springframework/cglib/proxy/Callback;)V Java设计模式-代理模式之动态代理(附源代码分析)