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设计模式-代理模式之动态代理(附源代码分析)

java代理模式

JAVA设计模式 -- 代理模式

Java 代理模式讲解

Java设计模式——代理模式

Spring之代理模式