代理模式
1. 什么是代理模式
- 代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用;类比即为生活中的中介,用图示表明:
2. 代理模式的作用
- 中介隔离作用:在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。
- 开闭原则,增加功能:代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。代理类本身并不真正实现服务,而是通过调用委托类的相关方法,来提供特定的服务。真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能,我们就可以使用代理类来完成,而没必要打开已经封装好的委托类。
3. 代理模式中的三个角色
-
代理模式中一般存在三个角色:
- 如图中所示:
- 抽象角色:指代理角色和真实角色对外提供的公共方法,一般为一个接口
- 真实角色:需要实现抽象角色接口,定义了真实角色所要实现的业务逻辑,以便供代理角色调用。本质上就是真正实现业务逻辑的对象
- 代理角色:需要实现抽象角色接口,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。将统一的流程控制都放到代理角色中处理!
- 如图中所示:
4. 代理模式的两种方式
静态代理
-
什么是静态代理:
- 静态代理即我们需要手动去创建代理类,在程序运行之前,代理类的.class文件就已经被创建了
-
静态代理的优缺点:
- 优点:可以做到在符合开闭原则的情况下对目标对象进行功能扩展
- 缺点:一个代理类只能代理一个接口,如果存在多个服务接口,那么就得为每一个服务接口都创建一个代理类,工作量太大,不易管理。同时接口一旦发生改变,代理类也得相应修改
-
静态代理的使用:
- 创建抽象角色,即抽象接口
- 创建真实角色,即继承抽象接口并实现
- 创建代理角色,即包含真实角色,提供调用方式
//1. 创建抽象角色 package com.example.myclass; public interface fruit { public void apple(); } //2. 创建真实角色 package com.example.myclass.statics; import com.example.myclass.fruit; public class liFruit implements fruit { @Override public void apple() { System.out.println("新鲜苹果,包甜"); } } //3. 创建代理角色 package com.example.myclass.agnet; import com.example.myclass.fruit; import com.example.myclass.statics.liFruit; public class fruitAgent implements fruit { private liFruit li; public fruitAgent(liFruit a) { this.li = a; } private void before() { System.out.println("骑车取货送货"); } private void after() { System.out.println("售后服务"); } @Override public void apple() { this.before(); this.li.apple(); this.after(); } } //实际使用举例 public void main() { liFruit li = new liFruit(); fruitAgent firuteagent = new fruitAgent(li); firuteagent.apple(); }
动态代理
-
什么是动态代理
- 动态代理是程序运行时通过反射机制动态创建代理对象
-
动态代理的优缺点
- 优点:相对于静态代理,极大的减少类的数量,降低工作量,减少对业务接口的依赖,降低耦合,便于后期维护;同时在某些情况下是最大的优势,即可以统一修改代理类的方法逻辑,而不需要像静态代理需要修改每个代理类
- 缺点:因为使用的是反射,所以在运行时会消耗一定的性能;同时JDK代理只支持interface的动态代理,如果你再继续深究源码,会发现,所有动态生成的代理对象都有一个共同的父类,即都继承于Proxy;Java的单继承机制决定了无法支持class的动态代理,也就意味着你拿到动态生成的代理对象,只能调用其实现的接口里的方法,无法像静态代理中的代理类可以在内部扩展更多的功能
-
动态代理的使用
-
调用Proxy类进行创建一个对象O
-
在Proxy对象O中的invoke函数中进行对应逻辑的实现
-
调用O对象进行调用方法
//接口 package com.example.myclass; public interface fruit { public void apple(); } //真实角色 package com.example.myclass.statics; import com.example.myclass.fruit; public class liFruit implements fruit { @Override public void apple() { System.out.println("新鲜苹果,包甜"); } } //动态代理方式 public void main() { final liFruit liFruit = new liFruit(); Object o = Proxy.newProxyInstance(ExampleUnitTest.class.getClassLoader(), new Class[]{fruit.class, vegatable.class}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { method.invoke(liFruit, args); return null; } }); //只能通过接口去继承转换 fruit f = (fruit) o; f.apple(); }
5. 动态代理的实现原理
-
通过上面动态代理的实现,发现是通过
newProxyInstance()
函数去实现的,查看SDK中的代码实现@CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); //对接口进行拷贝,获取所有的接口 final Class<?>[] intfs = interfaces.clone(); // Android-removed: SecurityManager calls /* final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } */ /* * Look up or generate the designated proxy class. */ //通过拷贝出来的接口,拿到一个Class对象 Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { // Android-removed: SecurityManager / permission checks. /* if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } */ //通过反射去获取这个Class对象的构造器 final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { // BEGIN Android-removed: Excluded AccessController.doPrivileged call. /* AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); */ cons.setAccessible(true); // END Android-removed: Excluded AccessController.doPrivileged call. } //通过反射获得的构造器实例化出一个实例对象 return cons.newInstance(new Object[]{h}); } catch (IllegalAccessException|InstantiationException e) { throw new InternalError(e.toString(), e); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString(), t); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); } }
由上面的
newProxyInstance()
函数分析可以看出,本质上是通过这个接口去构建出对应接口的一个实例化对象;而常规的操作中,一个类的完整生命周期分为以下几个步骤: JAVA源文件(JAVA文件)–/编译/–>Java字节码(.class文件)–/类加载/–>Class对象–/实例化/–>实例对象---->卸载;- class对象的来源(.class文件)
- 在正常编译流程中,编译出来的Java字节码是以<.class>文件存储在硬盘中的,然后再通过类加载器根据JAVA字节码去构建出一个Class对象
- 而动态代理过程中,是直接在内存中去生成的,而不存在一个.class文件
那么问题又来了,动态代理的class对象是怎么在内存中生成的?这个生成的Class对象又是什么样子的呢?
- class对象的来源(.class文件)
-
动态代理的class对象是怎么生成的
-
首先从上面的
newProxyInstance()
中我们可以看到,class对象是通过getProxyClass0()
函数获得的private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) { if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } // If the proxy class defined by the given loader implementing // the given interfaces exists, this will simply return the cached copy; // otherwise, it will create the proxy class via the ProxyClassFactory /*根据源码注释,当loader里存在接口实现时,就直接返回loader拷贝;否则,就通过ProxyClassFactory方法去创建一个代理类*/ return proxyClassCache.get(loader, interfaces); }
-
本质上,是通过
proxyClassCache
去获得的,那么proxyClassCache
又是什么呢?查看JDK中Proxy
类的实现private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache(new Proxy.KeyFactory(), new Proxy.ProxyClassFactory());
-
排查后发现,是通过
ProxyClassFactory()
函数进行获取的private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> { private static final String proxyClassNamePrefix = "$Proxy"; private static final AtomicLong nextUniqueNumber = new AtomicLong(); private ProxyClassFactory() { } public Class<?> apply(ClassLoader var1, Class<?>[] var2) { IdentityHashMap var3 = new IdentityHashMap(var2.length); Class[] var4 = var2; int var5 = var2.length; for(int var6 = 0; var6 < var5; ++var6) { Class var7 = var4[var6]; Class var8 = null; try { var8 = Class.forName(var7.getName(), false, var1); } catch (ClassNotFoundException var15) { } if (var8 != var7) { throw new IllegalArgumentException(var7 + " is not visible from class loader"); } //这里会判断动态代理是不是接口,如果不是接口,会在这里直接抛异常 if (!var8.isInterface()) { throw new IllegalArgumentException(var8.getName() + " is not an interface"); } if (var3.put(var8, Boolean.TRUE) != null) { throw new IllegalArgumentException("repeated interface: " + var8.getName()); } } String var16 = null; byte var17 = 17; Class[] var18 = var2; int var20 = var2.length; for(int var21 = 0; var21 < var20; ++var21) { Class var9 = var18[var21]; int var10 = var9.getModifiers(); if (!Modifier.isPublic(var10)) { var17 = 16; String var11 = var9.getName(); int var12 = var11.lastIndexOf(46); String var13 = var12 == -1 ? "" : var11.substring(0, var12 + 1); if (var16 == null) { var16 = var13; } else if (!var13.equals(var16)) { throw new IllegalArgumentException("non-public interfaces from different packages"); } } } if (var16 == null) { var16 = "com.sun.proxy."; } long var19 = nextUniqueNumber.getAndIncrement(); String var23 = var16 + "$Proxy" + var19; //最终就是通过这个函数进行JAVA字节码生成的,可以看到最终生成的是一个byte[]数组 byte[] var22 = ProxyGenerator.generateProxyClass(var23, var2, var17); try { return Proxy.defineClass0(var1, var23, var22, 0, var22.length); } catch (ClassFormatError var14) { throw new IllegalArgumentException(var14.toString()); } } }
-
解析
generateProxyClass()
函数public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) { ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2); final byte[] var4 = var3.generateClassFile(); if (saveGeneratedFiles) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { try { int var1 = var0.lastIndexOf(46); Path var2; if (var1 > 0) { Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar)); Files.createDirectories(var3); var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class"); } else { var2 = Paths.get(var0 + ".class"); } Files.write(var2, var4, new OpenOption[0]); return null; } catch (IOException var4x) { throw new InternalError("I/O exception saving generated file: " + var4x); } } }); } return var4; }
-
至此,后续代码没有必要再看了,我们可以得知,最终的class对象是通过
generateProxyClass()
函数获取的
-
-
动态代理的class对象中的代码到底是什么样的
-
由上面的动态代理的class对象是怎么生成的探究,我们得知可以通过
generateProxyClass()
函数获取的,那么我们可以调用该函数,获取该class对象,将其保存到真实文件中来查看//使用FileOutputStream,将内存中构建的类输出到文件中 //1. 创建抽象角色 package com.example.lib; public interface test { public void tt(); } //2. 将动态代理在内存中的类输出到文件中来 //要使用ProxyGenerator.generateProxyClass方法,需要导入这个包 import sun.misc.ProxyGenerator; public class MyClass { public static void main(String[] args) throws Exception { proxy(); } private static void proxy() throws IOException { String name = test.class.getName() + "$Proxy0"; //生成代理指定接口的Class数据 byte[] bytes = ProxyGenerator.generateProxyClass(name, new Class[]{test.class}); FileOutputStream fos = new FileOutputStream("lib/" + name + ".class"); fos.write(bytes); fos.close(); } }
- 通过这个方式,将内存中创建的class类完整的导入到文件中,此时我们可以打开这个类,看一下其内部的代码
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package com.example.lib; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class test$Proxy0 extends Proxy implements test { private static Method m1; private static Method m2; private static Method m3; private static Method m0; public test$Proxy0(InvocationHandler var1) throws { //构造方法中,调用了super(var1) //其中var1就是我们的InvocationHandler,而super其实就是Proxy,进入查看 /** * protected Proxy(InvocationHandler var1) { * Objects.requireNonNull(var1); * this.h = var1; * } */ //在Proxy的构造函数中,我们将InvocationHandler赋值到了this.h上 super(var1); } public final boolean equals(Object var1) throws { try { return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final String toString() throws { try { return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final void tt() throws { try { //由上面的分析,我们可以知道,h其实就是InvocationHandler,所以,当我们调用 //接口中的tt()方法,本质上我们就是调用了InvocationHandler的invoke方法, //即回调到了newProxyInstance中的invoke()方法 //而这个m3,看下面的静态代码块 super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final int hashCode() throws { try { return (Integer)super.h.invoke(this, m0, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m2 = Class.forName("java.lang.Object").getMethod("toString"); //从这里我们可以看到,m3实际上就是通过反射获得的test接口中的tt方法 m3 = Class.forName("com.example.lib.test").getMethod("tt"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
-
由此,我们动态代理的原理探究也就告一段落了,在函数实现的时候,需要注意:
-
import sun.misc.ProxyGenerator;
必须是在java模块中进行导入,查看Android SDK中的方法/** * A factory function that generates, defines and returns the proxy class given * the ClassLoader and array of interfaces. */ 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 int accessFlags = Modifier.PUBLIC | Modifier.FINAL; /* * 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)) { accessFlags = Modifier.FINAL; 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 the default package. proxyPkg = ""; } { //此处的说明表示Android SDK中的实现和JDK中的是不同的 // Android-changed: Generate the proxy directly instead of calling // through to ProxyGenerator. List<Method> methods = getMethods(interfaces); Collections.sort(methods, ORDER_BY_SIGNATURE_AND_SUBTYPE); validateReturnTypes(methods); List<Class<?>[]> exceptions = deduplicateAndGetExceptions(methods); Method[] methodsArray = methods.toArray(new Method[methods.size()]); Class<?>[][] exceptionsArray = exceptions.toArray(new Class<?>[exceptions.size()][]); /* * Choose a name for the proxy class to generate. */ long num = nextUniqueNumber.getAndIncrement(); String proxyName = proxyPkg + proxyClassNamePrefix + num; //SDK中用的是该方式,而非JDK中的ProxyGenerator.generateProxyClass()方法 return generateProxy(proxyName, interfaces, loader, methodsArray, exceptionsArray); } } }
而这也导致了,在Android模块中,我们无法使用
ProxyGenerator.generateProxyClass()
方法,且import sun.misc.ProxyGenerator;
该包也无法在Android中正常导入 -
使用Android studio,还需要进行如下设置,否则也无法编译通过,原因还是在于
import sun.misc.ProxyGenerator;
包的导入
-
-
-
6. 优秀博客: