在我的前一篇博文静态代理中,使用静态代理模式时,我们需要在程序加载执行前,手动的创建好每个目标对象类的代理类。这样就导致我们如果有很多个需要被代理的类时,就必须手动的去创建好所有的每一个代理类,这样就会生成很多的代理文件,不易于代理的维护和管理。有没有什么办法可以不用生成这么多代理类呢?动态代理
一 什么是动态代理
代理类在程序运行时才被创建出来的方式称为动态代理。在这种方式中,我们不需要在程序执行前去生成对应的代理类,只需要在程序执行过程中,根据我们传递的目标对象去动态的创建即可。相比较静态代理,这种方式不需要我们去手动创建大批量的文件,更易于代理对象及方法的统一管理维护,比如我们需要对代理类做方法增强时就不需要去修改每一个代理类。
二 动态代理实现
创建两个接口
1 public interface ICatDao { 2 3 /** 4 * 描述自己 5 */ 6 void desc(); 7 8 }
1 public interface IDogDao { 2 3 /** 4 * 描述自己 5 */ 6 void desc(); 7 8 }
创建接口的实现类
1 public class CatDaoImpl implements ICatDao { 2 @Override 3 public void desc() { 4 System.out.println("<<-----------喵喵----------->>"); 5 } 6 }
1 public class DogDaoImpl implements IDogDao { 2 @Override 3 public void desc() { 4 System.out.println("<<-----------旺旺----------->>"); 5 } 6 }
创建动态代理类实现 InvocationHandler接口(JDK动态代理必须实现这个接口),我们使用提供的目标对象调用getProxy方法来生成代理类,执行目标对象提供的方法时会通过反射执行invoke方法执行
1 public class DynamicProxy implements InvocationHandler { 2 3 /** 4 * 目标对象 5 */ 6 private Object target; 7 8 public DynamicProxy() { 9 } 10 11 public Object getProxy(Object intf){ 12 this.target = intf; 13 //args1:类加载器 14 //args2:目标对象接口方法 15 //InvocationHandler接口。所有动态代理类的方法调用,都会交由InvocationHandler接口实现类里的invoke()方法去处理 16 return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this); 17 } 18 19 @Override 20 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 21 method.invoke(target, args); 22 return null; 23 } 24 25 }
测试,创建main方法生成代理类,执行方法
1 public static void main(String[] args) { 2 3 ICatDao catDao = new CatDaoImpl(); 4 ICatDao catDaoProxy = (ICatDao) new DynamicProxy().getProxy(catDao); 5 catDaoProxy.desc(); 6 7 IDogDao dagDao = new DogDaoImpl(); 8 IDogDao dagDaoProxy = (IDogDao) new DynamicProxy().getProxy(dagDao); 9 dagDaoProxy.desc(); 10 11 }
执行结果如下,可以看到动态的生成了每一个目标对象,且可以正常执行
如果我们需要对做方法增强,我们只需要修改invoke就可以了,如
1 @Override 2 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 3 System.out.println("方法【"+method.getName()+"】要开始执行了"); 4 method.invoke(target, args); 5 System.out.println("方法【"+method.getName()+"】已经执行结束"); 6 return null; 7 }
执行测试方法,结果如下,可以看到对所有的代理类的方法都做了增强
三 源码分析
代理对象类生成是调用Proxy类的newProxyInstance方法实现的,我们看看具体的方法
1 /** 2 * 3 * @param loader 定义代理类的类加载器 4 * @param interfaces 要实现的代理类的接口列表,不能超过 65535 5 * @param h 6 * @return 7 * @throws IllegalArgumentException 8 */ 9 @CallerSensitive 10 public static Object newProxyInstance(ClassLoader loader, 11 Class<?>[] interfaces, 12 InvocationHandler h) 13 throws IllegalArgumentException 14 { 15 // InvocationHandler 不能为空 16 Objects.requireNonNull(h); 17 18 final Class<?>[] intfs = interfaces.clone(); 19 final SecurityManager sm = System.getSecurityManager(); 20 if (sm != null) { 21 //校验接口是否可以被访问 22 checkProxyAccess(Reflection.getCallerClass(), loader, intfs); 23 } 24 25 //生成代理类 26 Class<?> cl = getProxyClass0(loader, intfs); 27 28 //用指定的InvocationHandler调用其构造函数 29 try { 30 if (sm != null) { 31 //对代理类进行权限校验 32 checkNewProxyPermission(Reflection.getCallerClass(), cl); 33 } 34 35 //根据参数生成构造器 36 final Constructor<?> cons = cl.getConstructor(constructorParams); 37 38 final InvocationHandler ih = h; 39 40 if (!Modifier.isPublic(cl.getModifiers())) { 41 AccessController.doPrivileged(new PrivilegedAction<Void>() { 42 public Void run() { 43 cons.setAccessible(true); 44 return null; 45 } 46 }); 47 } 48 49 //使用构造器生成实例 50 return cons.newInstance(new Object[]{h}); 51 52 } catch (IllegalAccessException|InstantiationException e) { 53 throw new InternalError(e.toString(), e); 54 } catch (InvocationTargetException e) { 55 Throwable t = e.getCause(); 56 if (t instanceof RuntimeException) { 57 throw (RuntimeException) t; 58 } else { 59 throw new InternalError(t.toString(), t); 60 } 61 } catch (NoSuchMethodException e) { 62 throw new InternalError(e.toString(), e); 63 } 64 }
1 private static Class<?> getProxyClass0(ClassLoader loader, 2 Class<?>... interfaces) { 3 if (interfaces.length > 65535) { 4 throw new IllegalArgumentException("interface limit exceeded"); 5 } 6 7 //如果实现给定接口的给定加载器定义的代理类存在,那么它将返回缓存的副本; 否则,它将通过ProxyClassFactory创建代理类 8 return proxyClassCache.get(loader, interfaces); 9 }