动态代理和静态代理一般在设计模式中的定义为代理设计模式
定义: 为其他对象提供一种代理以控制对这个对象的访问
使用场景: 当无法或者不想直接访问某个对象时,或者访问对象存在一定的困难,可以通过代理对象来间接访问,为了保证客户端使用的透明性,委托对象和代理对象需要实现相同的接口
一般有 3 种角色
- 抽象主题类:一般指的是真实主题类和代理类的共性接口,或者叫目标接口
- 真实主题类:一般指的是有真实的目标需求的类,或者叫被代理类
- 代理类:一般指的是代理真实主题类,去完成真实主题类想要完成的事情,也就是代理,对真实主题类存在引用关系
静态代理
假设有 IBank 抽象主题类,也就是接口,代理类和被代理类都需要实现的共性接口,完成实际要做的事情
1 2 3 4 5 6 7 8 |
// 目标业务接口 public interface IBank { /** * 办卡 */ void applyBank(); } |
被代理类对象,有真实需求的目标用户
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// 某男士 public class Man implements IBank { private String name; public Man(String name) { this.name = name; } @Override public void applyBank() { System.out.println(name + " 需要申请办卡 "); } } |
代理对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// 银行办卡工作人员 public class BankWorker implements IBank { private IBank mIBank; //代理对象给被代理对象 办理业务 public BankWorker(IBank iBank) { this.mIBank = iBank; } @Override public void applyBank() { System.out.println("请问需要办理什么也去"); mIBank.applyBank(); System.out.println("办理完毕"); } } |
这里简单解释一下,也就是说有某个男士想要办理银行的办卡业务,但是他并不知道具体的流程是怎么样的,所以他需要一个代理人去帮他完成办卡业务,那么这个时候,代理对象也需要知道他具体要办的是什么业务,所以都需要实现目标业务接口
假如这个时候,这个男士又要办理其他的业务了,那么需要在目标接口中增加方法,同时代理对象和被代理对象都需要实现,不太方便,那么这就是静态代理,也就是有一个一对一的关系,其实代理对象可以使用 Java 提供的一个 Proxy 动态代理类完成,那么在编译的时候无需实现方法
动态代理
假设还是上述的银行办卡业务
1 2 3 4 5 6 7 8 |
// 目标接口 public interface IBank { /** * 办卡 */ void applyBank(); } |
被代理对象
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class Man implements IBank { private String name; public Man(String name) { this.name = name; } @Override public void applyBank() { System.out.println(name + " 需要申请办卡 "); } } |
动态代理对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public class BankInvocationHandler implements InvocationHandler { private Object mObject; /** * @param object 被代理对象 */ public BankInvocationHandler(Object object) { this.mObject = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // System.out.println("method " + method.getName()); System.out.println("需要办理什么业务"); // 反射执行方式 method.invoke(mObject, args); // 执行的就是 mObject 被代理对象的方法 System.out.println("办理完毕"); return null; } } |
客户端进行调用
1 2 3 4 5 6 7 8 |
Man man = new Man("xiaoming"); // 返回的是 接口的实例对象 IBank iBank = (IBank) Proxy.newProxyInstance(IBank.class.getClassLoader(), new Class[]{IBank.class},new BankInvocationHandler(man)); //办理业务 iBank.applyBank(); |
那么动态代理就已经完成了,那么回到上述刚才提到的一个问题,如果是静态代理的话,如果增加了一个新的挂失卡的业务的话,那么静态代理中的目标接口、被代理对象,代理对象,都需要需要这个方法,这样不太方法,那么假如是这个动态代理又是怎样的呢?
动态代理只需要目标接口中增加业务,被代理对象中,增加业务,即可,和上述相比是不是更加方便了一些,少了一些操作,少了一个代理对象
那么他是如何完成这个动作的呢 ? 它主要是通过这个方法 Proxy.newProxyInstance 去创建了一个对象,我们看看源码是如何完成的
这里可以通过 Debug 看看这个对象到底是什么,可以发现打印了一个 $Proxy0@463 的对象
Proxy.newProxyInstance 的源码,以下省略部分代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { if (h == null) { throw new NullPointerException(); } /* * Look up or generate the designated proxy class. */ // 获取class 类 Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { // 获取了构造方法 final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) { // create proxy instance with doPrivilege as the proxy class may // implement non-public interfaces that requires a special permission return AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { // 创建了实例 return newInstance(cons, ih); } }); } else { return newInstance(cons, ih); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); } } |
上面我们发现通过 Class<?> cl = getProxyClass0(loader, intfs) 获取了 Class, 然后通过构造的方式反射创建实例对象,那么这里主要看 getProxyClass0 是如何创建的
1 2 3 4 5 6 7 8 9 |
private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) { if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } // 缓存中获取 return proxyClassCache.get(loader, interfaces); } |
可以发现这里做了缓存,继续深入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public V get(K key, P parameter) { Objects.requireNonNull(parameter); expungeStaleEntries(); Object cacheKey = CacheKey.valueOf(key, refQueue); // lazily install the 2nd level valuesMap for the particular cacheKey ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey); if (valuesMap == null) { ConcurrentMap<Object, Supplier<V>> oldValuesMap = map.putIfAbsent(cacheKey, valuesMap = new ConcurrentHashMap<>()); if (oldValuesMap != null) { valuesMap = oldValuesMap; } } // create subKey and retrieve the possible Supplier<V> stored by that // subKey from valuesMap Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); Supplier<V> supplier = valuesMap.get(subKey); Factory factory = null; } |
这里主要使用的是 subKeyFactory.apply(key, parameter) 来创建的,我们继续看看里面干了什么,这个类其实是 ProxyClassFactory 中处理的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
private static final String proxyClassNamePrefix = "$Proxy"; private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> { // prefix for all proxy class names private static final String proxyClassNamePrefix = "$Proxy"; // next number to use for generation of unique proxy class names private static final AtomicLong nextUniqueNumber = new AtomicLong(); @Override public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) { Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); for (Class<?> intf : interfaces) { /* * Verify that the class loader resolves the name of this * interface to the same Class object. */ Class<?> interfaceClass = null; try { interfaceClass = Class.forName(intf.getName(), false, loader); } catch (ClassNotFoundException e) { } if (interfaceClass != intf) { throw new IllegalArgumentException( intf + " is not visible from class loader"); } /* * Verify that the Class object actually represents an * interface. */ if (!interfaceClass.isInterface()) { throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface"); } /* * Verify that this interface is not a duplicate. */ if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) { throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName()); } } String proxyPkg = null; // package to define proxy class in /* * Record the package of a non-public proxy interface so that the * proxy class will be defined in the same package. Verify that * all non-public proxy interfaces are in the same package. */ for (Class<?> intf : interfaces) { int flags = intf.getModifiers(); if (!Modifier.isPublic(flags)) { String name = intf.getName(); int n = name.lastIndexOf('.'); String pkg = ((n == -1) ? "" : name.substring(0, n + 1)); if (proxyPkg == null) { proxyPkg = pkg; } else if (!pkg.equals(proxyPkg)) { throw new IllegalArgumentException( "non-public interfaces from different packages"); } } } if (proxyPkg == null) { // if no non-public proxy interfaces, use com.sun.proxy package proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; } /* * Choose a name for the proxy class to generate. */ // 数字叠加 long num = nextUniqueNumber.getAndIncrement(); // 代理类名字的由来 proxyClassNamePrefix 就是 $Proxy String proxyName = proxyPkg + proxyClassNamePrefix + num; /* 生成了一个代理类 class 的一个数组 * Generate the specified proxy class. */ byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces); } |
到了这里我们可以发现动态的创建了一个代理类的一个数组,也知道了名字的由来了,那么生成的代理类到底长什么样子呢 ?我们通过一个工具类,输出到一个文件中进行查看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public class ProxyUtils { public static void generateClassFile(Class clazz, String proxyName) { /*ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags);*/ byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, new Class[]{clazz}); String paths = clazz.getResource(".").getPath(); System.out.println(paths); FileOutputStream out = null; try { out = new FileOutputStream(paths + proxyName + ".class"); out.write(proxyClassFile); out.flush(); } catch (Exception e) { e.printStackTrace(); } finally { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
public final class BankInvocationHandler extends Proxy implements Man { private static Method m1; private static Method m9; private static Method m2; private static Method m6; private static Method m3; private static Method m5; private static Method m8; private static Method m4; private static Method m10; private static Method m0; private static Method m7; public BankInvocationHandler(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { // 省略部分代码 } public final void notify() throws { // 省略部分代码 } public final String toString() throws { // 省略部分代码 } public final void wait(long var1) throws InterruptedException { // 省略部分代码 } // 挂失业务 public final void loseBank() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final void wait(long var1, int var3) throws InterruptedException { // 省略部分代码 } public final Class getClass() throws { // 省略部分代码 } public final void applyBank() throws { try { super.h.invoke(this, m4, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final void notifyAll() throws { // 省略部分代码 } public final int hashCode() throws { // 省略部分代码 } public final void wait() throws InterruptedException { // 省略部分代码 } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m9 = Class.forName("com.fangsf.java_lib.proxy.Man").getMethod("notify"); m2 = Class.forName("java.lang.Object").getMethod("toString"); m6 = Class.forName("com.fangsf.java_lib.proxy.Man").getMethod("wait", Long.TYPE); m3 = Class.forName("com.fangsf.java_lib.proxy.Man").getMethod("loseBank"); m5 = Class.forName("com.fangsf.java_lib.proxy.Man").getMethod("wait", Long.TYPE, Integer.TYPE); m8 = Class.forName("com.fangsf.java_lib.proxy.Man").getMethod("getClass"); // 办理卡方法 m4 = Class.forName("com.fangsf.java_lib.proxy.Man").getMethod("applyBank"); m10 = Class.forName("com.fangsf.java_lib.proxy.Man").getMethod("notifyAll"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); m7 = Class.forName("com.fangsf.java_lib.proxy.Man").getMethod("wait"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } } |
这里我们可以看到继承一个 proxy 的类,然后还实现了一个 Man 类 ???众所周知实现不是只能实现接口吗?怎么这里实现了一个类呢,这里其实是一个障眼法,其实实现的是 IBack 接口,那么就有了目标接口的实际需求了。
我们可以发现一个重要的执行代码 super.h.invoke(this, m4, (Object[])null); 其实 super.h 就是我们创建的代理类BankInvocationHandler ,然后执行了 m4, m4 其实就是这个方法 Class.forName(“com.fangsf.java_lib.proxy.Man”).getMethod(“applyBank”)
到这里基本就结束了,我们可以发现其实代理对象其实也是有的,只不过是 Java 帮助我们动态生成了,所以我们不用去写这个类,即使后面增加了目标业务需求,只需要代理对象实现相应方法即可,我们的动态代理类会自动生成的。更加的方便,不过需要注意的是动态代理用了大量的反射,比静态代理会更加耗性能。