什么是代理模式?
定义
为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
——百度百科
代理模式的角色
抽象角色:代理对象和真实对象的共同接口
代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能够代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。
示意图
代理模式的分类及使用
-
静态代理
1 package staticProxy; 2 3 // 抽象角色,真是对象与代理对象的共同接口 4 public interface Subject { 5 public void request(); 6 }
1 package staticProxy; 2 3 //代理对象,用来被客户端直接调用的类,内部被注入真实对象,可以在调用真是对象的方法前后做预处理和后处理 4 public class ProxyClass implements Subject { 5 6 Subject subject; 7 8 ProxyClass (Subject subject) { 9 this.subject = subject; 10 } 11 12 @Override 13 public void request() { 14 System.out.println("prefix-process!"); 15 subject.request(); 16 System.out.println("suffix-process!"); 17 } 18 19 }
1 package staticProxy; 2 3 //真实对象,委托类 4 public class RealClass implements Subject { 5 6 @Override 7 public void request() { 8 System.out.println("I'm realClass!"); 9 } 10 11 }
1 package staticProxy; 2 3 //客户端 4 public class StaticProxy { 5 public static void main(String[] args) { 6 Subject subject = new ProxyClass(new RealClass()); 7 8 subject.request(); 9 } 10 }
静态代理的缺点很显著,对每一个委托类都需要创建一个代理类,为了解决这个问题,java提供了动态代理。
-
动态代理
抽象角色与真实角色的定义和静态代理完全一致,这里不再重复定义
动态代理类需要继承自InvocationHandler接口,并实现其中的invoke方法。
1 package dynamicProxy; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 6 public class ProxyClass implements InvocationHandler { 7 8 Object subject; 9 10 public ProxyClass(Object subject) { 11 this.subject = subject; 12 } 13 14 @Override 15 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 16 System.out.println("prefix-process!"); 17 method.invoke(subject, args); 18 System.out.println("suffix-process!"); 19 return null; 20 } 21 22 }
1 package dynamicProxy; 2 3 import java.lang.reflect.Proxy; 4 5 public class DynamicProxy { 6 public static void main(String[] args) { 7 8 Subject subject = (Subject) Proxy.newProxyInstance(RealClass.class.getClassLoader(), 9 new Class[] {Subject.class}, new ProxyClass(new RealClass())); 10 11 subject.request(); 12 } 13 }
动态代理的实现原理
动态代理的实现主要依赖于java.lang.reflect.InvocationHandler接口与java.lang.reflect.Proxy类,其实现原理是基于java的反射技术。
InvocationHandler接口
动态代理类需要继承自InvocationHandler接口,此接口中只包含一个方法invoke方法,接口原型如下:
1 package java.lang.reflect; 2 3 public interface InvocationHandler { 4 5 /** 6 * proxy:代表代理对象本身,用于调用本代理对象的其他方法 7 * method:代表正在被调用的委托类的方法 8 * args:代表调用方法的参数 9 */ 10 public Object invoke(Object proxy, Method method, Object[] args) 11 throws Throwable; 12 }
Proxy类
Proxy类中定义了很多的方法,但根据上面动态代理的应用我们看到,最重要的一个方法就是newProxyInstance方法,该方法的作用就是动态创建一个代理类对象:
1 /** 2 * loader代表了委托类的类加载器 3 * interfaces代表了委托类的接口数组 4 * h代表委托类的实例 5 */ 6 @CallerSensitive 7 public static Object newProxyInstance(ClassLoader loader, 8 Class<?>[] interfaces, 9 InvocationHandler h) 10 throws IllegalArgumentException 11 { 12 // 判断委托类实例是否为空,如果未空抛异常 13 Objects.requireNonNull(h); 14 15 final Class<?>[] intfs = interfaces.clone(); 16 final SecurityManager sm = System.getSecurityManager(); 17 if (sm != null) { 18 checkProxyAccess(Reflection.getCallerClass(), loader, intfs); 19 } 20 21 /* 22 * 获取获取代理类的Class实例 23 */ 24 Class<?> cl = getProxyClass0(loader, intfs); 25 26 /* 27 * Invoke its constructor with the designated invocation handler. 28 */ 29 try { 30 if (sm != null) { 31 checkNewProxyPermission(Reflection.getCallerClass(), cl); 32 } 33 34 //获取代理类的Constructor对象 35 final Constructor<?> cons = cl.getConstructor(constructorParams); 36 final InvocationHandler ih = h; 37 if (!Modifier.isPublic(cl.getModifiers())) { 38 AccessController.doPrivileged(new PrivilegedAction<Void>() { 39 public Void run() { 40 cons.setAccessible(true); 41 return null; 42 } 43 }); 44 } 45 46 //利用反射原理中使用constructor动态创建动态代理类型 47 return cons.newInstance(new Object[]{h}); 48 } catch (IllegalAccessException|InstantiationException e) { 49 throw new InternalError(e.toString(), e); 50 } catch (InvocationTargetException e) { 51 Throwable t = e.getCause(); 52 if (t instanceof RuntimeException) { 53 throw (RuntimeException) t; 54 } else { 55 throw new InternalError(t.toString(), t); 56 } 57 } catch (NoSuchMethodException e) { 58 throw new InternalError(e.toString(), e); 59 } 60 }
动态代理的应用场景
动态代理最著名的应用场景就是spring中的aop