代理模式
使用代理模式必须要让代理类和目标类实现相同的接口,客户端通过代理类来调用目标方法,代理类会将所有的方法调用分派到目标对象上反射执行,还可以在分派过程中添加"前置通知"和后置处理(如在调用目标方法前校验权限,在调用完目标方法后打印日志等)等功能。

使用动态代理的五大步骤
1.通过实现InvocationHandler接口来自定义自己的InvocationHandler;
2.通过Proxy.getProxyClass获得动态代理类
3.通过反射机制获得代理类的构造方法,方法签名为getConstructor(InvocationHandler.class)
4.通过构造函数获得代理对象并将自定义的InvocationHandler实例对象传为参数传入
5.通过代理对象调用目标方法
动态代理的使用
例1(方式一)
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 | public class MyProxy { public interface IHello{ void sayHello(); } static class Hello implements IHello{ public void sayHello() { System.out.println("Hello world!!"); } } //自定义InvocationHandler static class HWInvocationHandler implements InvocationHandler{ //目标对象 private Object target; public HWInvocationHandler(Object target){ this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("------插入前置通知代码-------------"); //执行相应的目标方法 Object rs = method.invoke(target,args); System.out.println("------插入后置处理代码-------------"); return rs; } } public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetExc eption, InstantiationException { //生成$Proxy0的class文件 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); //获取动态代理类 Class proxyClazz = Proxy.getProxyClass(IHello.class.getClassLoader(),IHello.class); //获得代理类的构造函数,并传入参数类型InvocationHandler.class Constructor constructor = proxyClazz.getConstructor(InvocationHandler.class); //通过构造函数来创建动态代理对象,将自定义的InvocationHandler实例传入 IHello iHello = (IHello) constructor.newInstance(new HWInvocationHandler(new Hello())); //通过代理对象调用目标方法 iHello.sayHello(); }} |
代理类Class源码样例
$Proxy0.class
来看看例1(MyProxy)的代理类是怎样的?
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 | public final class $Proxy0 extends Proxy implements IHello { //继承了Proxy类和实现IHello接口 //变量,都是private static Method XXX private static Method m3; private static Method m1; private static Method m0; private static Method m2; //代理类的构造函数,其参数正是是InvocationHandler实例,Proxy.newInstance方法就是通过通过这个构造函数来创建代理实例的 public $Proxy0(InvocationHandler var1) throws { super(var1); } //接口代理方法 public final void sayHello() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } //以下Object中的三个方法 public final boolean equals(Object var1) throws { try { return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue(); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final int hashCode() throws { try { return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue(); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } 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); } } //对变量进行一些初始化工作 static { try { m3 = Class.forName("com.mobin.proxy.IHello").getMethod("sayHello", new Class[0]); m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")}); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } }} |
由于JDK生成的代理类已经继承了Proxy(Java只支持单一继承),因此目标类必须是接口。代理类也实现了目标接口,因此在
代理类中,实现了目标接口中定义的方法。调用代理类中的代理方法时,都会通过 super.h.invoke(this, m3, (Object[])null);
调用InvocationHandler的invoke()方法,传入代理对象this,Method方法和方法参数,由于在handler中持有了目标类的实例,因此在InvocationHandler 的
invoke()方法中回掉目标对象的方法,并且在目标方法调用前,后,返回后,异常情况下进行处理(如:日志、安全、缓存等操作)
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("------插入前置通知代码-------------"); //执行相应的目标方法 Object rs = method.invoke(target,args); System.out.println("------插入后置处理代码-------------"); return rs; }
本文深入讲解Java动态代理的实现原理及步骤,通过示例代码演示如何利用代理模式增强方法调用的功能,包括权限验证和日志记录等。
2892

被折叠的 条评论
为什么被折叠?



