代理模式在java中随处可见,其他编程语言也一样,它的作用就是用来解耦的。代理模式又分为静态代理和动态代理。 先从简单的开始,来一段静态代理的示例代码:
/** * 接口 */ interface Person { void study(); } /** * 被代理类 */ class Student implements Person { @Override public void study() { System.out.print("study"); } } /** * 针对Student创建一个代理类 */ class StudentProxy implements Person { /** * 需要被代理类作为其属性 */ private Student student; /** * 通过构造函数将被代理类设置进来 * * @param student */ public StudentProxy(Student student) { this.student = student; } /** * 同样是study,代理类在原有的功能上做了增强 */ @Override public void study() { //前置增强 System.out.print("开始学习"); //调用被代理实例的study方法 student.study(); //后置增强 System.out.print("学习结束"); } } 复制代码
测试代码:
public static void main(String[] args) { Person person = new Student(); person.study(); //输出结果:study person = new StudentProxy(new Student()); person.study(); //输出结果:开始学习study学习结束 } 复制代码
但是,静态代理会带来的一个问题是,如果需要代理的类特别多,我们就需要有同等数量的代理类,这样做显然是不行的。在了解了类加载原理的前提下,我们可以动态生成代理类。JDK动态代理
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; class ProxyInvocationHandler implements InvocationHandler { /** * 被代理对象 */ private Object object; /** * 利用构造函数设置被代理类属性 * * @param object */ public ProxyInvocationHandler(Object object) { this.object = object; } /** * 创建一个代理对象 * * @return */ public Object newProxyInstance() { /** * 获取被代理类的接口 */ Class<?>[] classes = this.object.getClass().getInterfaces(); /** * 创建代理对象 */ return Proxy.newProxyInstance(this.getClass().getClassLoader(), classes, this); } /** * 调用代理对象的方法 * * @param proxy * @param method * @param args * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.print("前置处理"); /** * 执行被代理对象方法 */ Object result = method.invoke(object); System.out.print("后置处理"); return result; } } 复制代码
测试代码:
public static void main(String[] args) { //创建一个InvocationHandler,并设置被代理对象 ProxyInvocationHandler handler = new ProxyInvocationHandler(new Student()); //创建代理对象 Person person = (Person) handler.newProxyInstance(); person.study(); //输出结果:前置处理study后置处理 } 复制代码
ProxyInvocationHandler针对于任何有接口的对象都可以创建对应的代理对象,这样的话,相对于静态代理的方式,我们就减少了很多工作啦。
但是,InvocationHandler到底是怎么做到可以动态创建代理对象的呢?1.其实我们可以结合静态代理的原理,静态代理的类是手工编写的,那么我们是否可以让代码自动生成对应的代理类呢?显然是可以的。2.我们如果自动生成了代理类,我们怎么让JVM知道它的存在呢?答案就在动态代理的代码中:ClassLoader
/** * 创建一个代理对象 * * @return */ public Object newProxyInstance() { /** * 获取被代理类的接口 */ Class<?>[] classes = this.object.getClass().getInterfaces(); /** * 创建代理对象 */ return Proxy.newProxyInstance(this.getClass().getClassLoader(), classes, this); } 复制代码
我们把上面这段代码拿出来看一下: 1.首先拿到被代理对象的接口。举个例子:如果这个被代理对象是Student,那么它的接口就是Person。 2.Proxy.newProxyInstance()里面有三个参数,第一个是ClassLoader,第二个是Class<?>[],第三个是InvocationHandler。 那么我大胆假设一下:1.利用字符串拼接的方式创建一个代理类实现指定的接口,并且把InvocationHandler对象作为它的属性。2.利用ClassLoader把创建出来的代理类加载进JVM,最后利用反射创建一个代理类实例返回按照上述假设,只要调用代理对象实现的方法,就将这个方法的调用委托给InvocationHandler对象的invoke方法,这样的话,就能实现增强处理。
为了验证我的假设,我把生成的代理类文件给出来:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy0 extends Proxy implements Person { /** * equals方法 */ private static Method m1; /** * Person的study方法 */ private static Method m3; /** * toString方法 */ private static Method m2; /** * hashCode方法 */ private static Method m0; /** * 构造函数,用于设置InvocationHandler */ public $Proxy0(InvocationHandler var1) throws { super(var1); } /** * 重写equals方法 */ public final boolean equals(Object var1) throws { try { /** * 委托给InvocationHandler处理 */ return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } /** * 实现study */ public final void study() throws { try { /** * 委托给InvocationHandler处理,这样我们就可以做前后增强 */ super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } /** * 重写toString() */ public final String toString() throws { try { /** * 委托给InvocationHandler处理 */ return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } /** * 重写hashCode */ public final int hashCode() throws { try { /** * 委托给InvocationHandler处理 */ 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")); m3 = Class.forName("Person").getMethod("study"); m2 = Class.forName("java.lang.Object").getMethod("toString"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } } 复制代码
到这里,小伙伴应该恍然大悟,完全就是静态代理嘛,只不过代码不再是手工编写,而是代码自动创建的,并且所有方法啥也没做,全部交给了InvocationHandler来处理。
JDK动态代理有一点限制,就是一定要有接口,如果没有接口怎么办,难道我们就不能创建代理对象了?接下来我们来看另一种创建代理的方式:CGLIB动态代理因为CGLIB不是JDK原生的,所以我们得引一个jar包:
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.10</version> </dependency> 复制代码
class ProxyMethodInterceptor implements MethodInterceptor { /** * 被代理对象 */ private Object object; /** * 利用构造函数设置被代理对象 * * @param object */ public ProxyMethodInterceptor(Object object) { this.object = object; } /** * 创建代理对象 * * @return */ public Object newProxyInstance() { /** * 创建Enhancer实例 */ Enhancer enhancer = new Enhancer(); /** * 设置被代理类 */ enhancer.setSuperclass(this.object.getClass()); /** * 设置回调 */ enhancer.setCallback(this); /** * 创建代理 */ return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.print("前置通知"); /** * 调用被代理对象方法 */ Object result = methodProxy.invokeSuper(o, objects); System.out.print("后置通知"); return result; } } 复制代码
我们按照惯例,再来一次猜想:1.既然接口是通过implements实现的代理,那没有接口是不是可以通过extends实现代理呢?貌似是没有问题的!2.那为什么这次创建代理的时候没有ClassLoader?其实在Enhancer里面还是通过getClassLoader()拿到的ClassLoader,原理不变同样为了证明咱们的猜想,我把CGLIB生成的类文件贴上来:
import java.lang.reflect.Method; import net.sf.cglib.core.ReflectUtils; import net.sf.cglib.core.Signature; import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.Factory; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; /** * 代理类,继承了Sudent */ public class Student$$EnhancerByCGLIB$$6f952e1b extends Student implements Factory { /** * 一开始是false,标记CGLIB$CALLBACK_0是否初始化 */ private boolean CGLIB$BOUND; /** * 暂时不讨论 */ public static Object CGLIB$FACTORY_DATA; /** * 用来存放回调,和线程绑定 */ private static final ThreadLocal CGLIB$THREAD_CALLBACKS; /** * 用来存放回调,用数组存放 */ private static final Callback[] CGLIB$STATIC_CALLBACKS; /** * 回调 */ private MethodInterceptor CGLIB$CALLBACK_0; /** * 暂不讨论 */ private static Object CGLIB$CALLBACK_FILTER; /** * study方法 */ private static final Method CGLIB$study$0$Method; /** * study代理方法 */ private static final MethodProxy CGLIB$study$0$Proxy; /** * 空参数 */ private static final Object[] CGLIB$emptyArgs; /** * equals方法 */ private static final Method CGLIB$equals$1$Method; /** * equals代理方法 */ private static final MethodProxy CGLIB$equals$1$Proxy; /** * toString方法 */ private static final Method CGLIB$toString$2$Method; /** * toString代理方法 */ private static final MethodProxy CGLIB$toString$2$Proxy; /** * hashCode方法 */ private static final Method CGLIB$hashCode$3$Method; /** * hashCode代理方法 */ private static final MethodProxy CGLIB$hashCode$3$Proxy; /** * clone方法 */ private static final Method CGLIB$clone$4$Method; /** * clone代理方法 */ private static final MethodProxy CGLIB$clone$4$Proxy; /** * 初始化调用 */ static void CGLIB$STATICHOOK1() { /** * 创建ThreadLocal实例 */ CGLIB$THREAD_CALLBACKS = new ThreadLocal(); /** * 空参数 */ CGLIB$emptyArgs = new Object[0]; /** * 拿到代理类自己的Class实例 */ Class var0 = Class.forName("Student$$EnhancerByCGLIB$$6f952e1b"); /** * 被代理类class */ Class var1; /** * 通过反射的方式拿到Object类的equals,toString,hashCode,clone方法 */ Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods()); /** * 把equals方法赋值给CGLIB$equals$1$Method */ CGLIB$equals$1$Method = var10000[0]; /** * 创建equals方法的代理方法 */ CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1"); /** * 把toString方法赋值给CGLIB$toString$2$Method */ CGLIB$toString$2$Method = var10000[1]; /** * 创建toString方法的代理方法 */ CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2"); /** * 把hashCode方法赋值给CGLIB$hashCode$3$Method */ CGLIB$hashCode$3$Method = var10000[2]; /** * 创建hashCode方法的代理方法 */ CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3"); /** * 把clone方法赋值给CGLIB$clone$4$Method */ CGLIB$clone$4$Method = var10000[3]; /** * 创建clone方法的代理方法 */ CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4"); /** * 被代理类的study方法 */ CGLIB$study$0$Method = ReflectUtils.findMethods(new String[]{"study", "()V"}, (var1 = Class.forName("Student")).getDeclaredMethods())[0]; /** * 创建代理类的study方法 */ CGLIB$study$0$Proxy = MethodProxy.create(var1, var0, "()V", "study", "CGLIB$study$0"); } /** * 调用父类(被代理类)的study */ final void CGLIB$study$0() { super.study(); } /** * 重写父类的study(也就是实现代理功能) */ public final void study() { /** * 拿到MethodInterceptor */ MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { //设置回调 CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if (var10000 != null) { //调用MethodInterceptor.intercept(这是重点),回到我们自己实现的MethodInterceptor中 var10000.intercept(this, CGLIB$study$0$Method, CGLIB$emptyArgs, CGLIB$study$0$Proxy); } else { //如果没有回调,就直接执行父类的study super.study(); } } /** * 调用父类(被代理类)的equals方法 * * @param var1 * @return */ final boolean CGLIB$equals$1(Object var1) { return super.equals(var1); } /** * 重写父类的equals方法(也就是实现代理功能) * * @param var1 * @return */ public final boolean equals(Object var1) { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if (var10000 != null) { Object var2 = var10000.intercept(this, CGLIB$equals$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy); return var2 == null ? false : (Boolean) var2; } else { return super.equals(var1); } } /** * 调用父类(被代理类)的toString方法 * * @return */ final String CGLIB$toString$2() { return super.toString(); } /** * 重写父类的toString方法(也就是实现代理功能) * * @return */ public final String toString() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } return var10000 != null ? (String) var10000.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy) : super.toString(); } /** * 调用父类(被代理类)的hashCode方法 * * @return */ final int CGLIB$hashCode$3() { return super.hashCode(); } /** * 重写父类的hashCode方法(也就是实现代理功能) * * @return */ public final int hashCode() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if (var10000 != null) { Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy); return var1 == null ? 0 : ((Number) var1).intValue(); } else { return super.hashCode(); } } /** * 调用父类(被代理类)的clone方法 * * @return * @throws CloneNotSupportedException */ final Object CGLIB$clone$4() throws CloneNotSupportedException { return super.clone(); } /** * 重写父类的clone方法(也就是实现代理功能) * * @return * @throws CloneNotSupportedException */ protected final Object clone() throws CloneNotSupportedException { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } return var10000 != null ? var10000.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy) : super.clone(); } /** * 获取一个代理方法 * * @param var0 * @return */ public static MethodProxy CGLIB$findMethodProxy(Signature var0) { String var10000 = var0.toString(); switch (var10000.hashCode()) { case -508378822: if (var10000.equals("clone()Ljava/lang/Object;")) { return CGLIB$clone$4$Proxy; } break; case 1826985398: if (var10000.equals("equals(Ljava/lang/Object;)Z")) { return CGLIB$equals$1$Proxy; } break; case 1876544780: if (var10000.equals("study()V")) { return CGLIB$study$0$Proxy; } break; case 1913648695: if (var10000.equals("toString()Ljava/lang/String;")) { return CGLIB$toString$2$Proxy; } break; case 1984935277: if (var10000.equals("hashCode()I")) { return CGLIB$hashCode$3$Proxy; } } return null; } /** * 设置回调 */ public Student$$EnhancerByCGLIB$$6f952e1b() { CGLIB$BIND_CALLBACKS(this); } /** * 把回调放进ThreadLocal中 * * @param var0 */ public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) { CGLIB$THREAD_CALLBACKS.set(var0); } /** * 设置回调 * @param var0 */ public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) { CGLIB$STATIC_CALLBACKS = var0; } /** * 初始化CGLIB$CALLBACK_0(设置回调) * * @param var0 */ private static final void CGLIB$BIND_CALLBACKS(Object var0) { Student$$EnhancerByCGLIB$$6f952e1b var1 = (Student$$EnhancerByCGLIB$$6f952e1b) var0; /** * 一开始CGLIB$BOUND就是false */ if (!var1.CGLIB$BOUND) { var1.CGLIB$BOUND = true; Object var10000 = CGLIB$THREAD_CALLBACKS.get(); if (var10000 == null) { var10000 = CGLIB$STATIC_CALLBACKS; if (var10000 == null) { return; } } /** * 给CGLIB$CALLBACK_0赋值 */ var1.CGLIB$CALLBACK_0 = (MethodInterceptor) ((Callback[]) var10000)[0]; } } /** * 创建代理对象 * @param var1 * @return */ public Object newInstance(Callback[] var1) { /** * 把回调放进ThreadLocal */ CGLIB$SET_THREAD_CALLBACKS(var1); /** * 创建一个代理对象 */ Student$$EnhancerByCGLIB$$6f952e1b var10000 = new Student$$EnhancerByCGLIB$$6f952e1b(); /** * 清除ThreadLocal中的回调 */ CGLIB$SET_THREAD_CALLBACKS((Callback[]) null); /** * 返回代理对象 */ return var10000; } /** * 创建代理对象(同上) * @param var1 * @return */ public Object newInstance(Callback var1) { CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1}); Student$$EnhancerByCGLIB$$6f952e1b var10000 = new Student$$EnhancerByCGLIB$$6f952e1b(); CGLIB$SET_THREAD_CALLBACKS((Callback[]) null); return var10000; } /** * 创建代理对象(同上) * @param var1 * @param var2 * @param var3 * @return */ public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) { CGLIB$SET_THREAD_CALLBACKS(var3); Student$$EnhancerByCGLIB$$6f952e1b var10000 = new Student$$EnhancerByCGLIB$$6f952e1b; switch (var1.length) { case 0: var10000.<init> (); CGLIB$SET_THREAD_CALLBACKS((Callback[]) null); return var10000; default: throw new IllegalArgumentException("Constructor not found"); } } /** * 获取回调 * @param var1 * @return */ public Callback getCallback(int var1) { CGLIB$BIND_CALLBACKS(this); MethodInterceptor var10000; switch (var1) { case 0: var10000 = this.CGLIB$CALLBACK_0; break; default: var10000 = null; } return var10000; } /** * 设置回调 * @param var1 * @param var2 */ public void setCallback(int var1, Callback var2) { switch (var1) { case 0: this.CGLIB$CALLBACK_0 = (MethodInterceptor) var2; default: } } /** * 创建回调数组 * @return */ public Callback[] getCallbacks() { CGLIB$BIND_CALLBACKS(this); return new Callback[]{this.CGLIB$CALLBACK_0}; } /** * 设置回调数组 * @param var1 */ public void setCallbacks(Callback[] var1) { this.CGLIB$CALLBACK_0 = (MethodInterceptor) var1[0]; } /** * 首先执行CGLIB$STATICHOOK1方法 */ static { CGLIB$STATICHOOK1(); } } 复制代码
根据上述的代码,我们可以肯定我们的猜想是正确的。不过CGLIB是以直接生成字节码的方式创建的代理类。 所谓的动态代理其实思想和静态代理一样,只不过我们将苦力活转变成了脑力活,使我们需要的代理对象可以自动生成。注意:因为final修饰的方法是不可以被重写的,也就意味着final修饰的方法不能够被代理
以上就是我对代理模式的简单剖析,感兴趣的小伙伴也可以根据原理自己实现一个创建代理对象的工具类。