Java三种代理模式:静态代理、动态代理和cglib代理 https://segmentfault.com/a/1190000011291179
Java 动态代理详解 https://juejin.cn/post/6844903744954433544#heading-3
静态代理 静态代理帮助我们实现功能增强的效果
我们可以在不入侵代理目标的源代码的情况下扩展他原来的方法
这种代理方式需要代理对象和目标对象实现一样的接口
缺点:
冗余。由于代理对象要实现与目标对象一致的接口,会产生过多的代理类。
不易维护。一旦接口增加方法,目标对象与代理对象都要进行修改。
动态代理 考虑到静态代理的缺点,我们如何改进:
让代理类动态生成,就不用去定义过多的代理类。
JDK动态代理 JDK动态代理主要涉及两个类:java.lang.reflect.Proxy 和 java.lang.reflect.InvocationHandler
先编写一个LogHandler来实现InvocationHandler接口
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 package com.jdkDemo;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.util.Date;public class LogHandler implements InvocationHandler { Object target; public LogHandler (Object target) { this .target = target; } @Override public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { before(); Object result = method.invoke(target, args); after(); return result; } public void before () { System.out.println(String.format("log start time [%s]" ,new Date ())); } public void after () { System.out.println(String.format("log end time [%s]" ,new Date ())); } }
然后用java.lang.reflect.Proxy 的newProxyInstance方法来构造一个指定接口的代理类的额一个新实例,所有方法会调用给定处理器(也就是LogHandler)的invoke方法
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 package com.jdkDemo;import com.jtDemo.UserService;import com.jtDemo.UserServiceImpl;import java.lang.reflect.Proxy;public class Client { public static void main (String[] args) { UserServiceImpl userServiceimpl = new UserServiceImpl (); ClassLoader classLoader = userServiceimpl.getClass().getClassLoader(); Class<?>[] interfaces = userServiceimpl.getClass().getInterfaces(); LogHandler handler = new LogHandler (userServiceimpl); UserService proxy = (UserService) Proxy.newProxyInstance(classLoader, interfaces, handler); proxy.select(); proxy.update(); } }
项目输出:
1 2 3 4 5 6 log start time [Sat Mar 12 09:02 :44 CST 2022 ] 查询方法 log end time [Sat Mar 12 09:02 :44 CST 2022 ] log start time [Sat Mar 12 09:02 :44 CST 2022 ] 更新方法 log end time [Sat Mar 12 09:02 :44 CST 2022 ]
可以发现传给代理的方法都被转发到了处理器LogHandler handler = new LogHandler(userServiceimpl);
中的invoke方法中
我们可以通过工具分析出构造出来的动态代理类:
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 import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.lang.reflect.UndeclaredThrowableException;import proxy.UserService;public final class UserServiceProxy extends Proxy implements UserService { private static Method m1; private static Method m2; private static Method m4; private static Method m0; private static Method m3; public UserServiceProxy (InvocationHandler var1) throws { super (var1); } public final boolean equals (Object var1) throws { } public final String toString () throws { } public final void select () throws { try { super .h.invoke(this , m4, (Object[])null ); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException (var3); } } public final int hashCode () throws { } public final void update () throws { try { super .h.invoke(this , m3, (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" ); m4 = Class.forName("proxy.UserService" ).getMethod("select" ); m0 = Class.forName("java.lang.Object" ).getMethod("hashCode" ); m3 = Class.forName("proxy.UserService" ).getMethod("update" ); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError (var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError (var3.getMessage()); } } }
可以看到动态代理类在执行方法的时候都是用handler中我们重写的invoke方法来调用的
UserServiceProxy 继承了 Proxy 类,并且实现了被代理的所有接口,以及equals、hashCode、toString等方法
由于 UserServiceProxy 继承了 Proxy 类,所以每个代理类都会关联一个 InvocationHandler 方法调用处理器
类和所有方法都被 public final
修饰,所以代理类只可被使用,不可以再被继承
每个方法都有一个 Method 对象来描述,Method 对象在static静态代码块中创建,以 m + 数字
的格式命名
调用方法的时候通过 super.h.invoke(this, m1, (Object[])null);
调用,其中的 super.h.invoke
实际上是在创建代理的时候传递给 Proxy.newProxyInstance
的 LogHandler 对象,它继承 InvocationHandler 类,负责实际的调用处理逻辑