如有错误请指正
1. 动态代理的作用:
1. 虚拟机生成的动态代理对象可以轻松地对原有方法进行各种重写
2. 若没有动态代理,想实现重写,必须做一个继承基类的子类
2. 实例演示:
package com.didi.test; public interface Person { String skill(); String play(); } package com.didi.test; public class Programmer implements Person{ @Override public String skill() { System.out.println("coding-------------------------"); return "调用skill方法"; } @Override public String play() { return null; } } package com.didi.test; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class MyInvocationHandler implements InvocationHandler { Programmer programmer; public MyInvocationHandler(Programmer programmer) { this.programmer = programmer; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before------------"); System.out.println(proxy.getClass().getName()); Object obj = method.invoke(programmer); System.out.println("after----------------------"); if(!method.getName().equals("skill")){ return "调用娱乐方法"; } return obj; } } package com.didi.test; import java.lang.reflect.Proxy; public class ProxTest { public static void main(String[] args) { Programmer p = new Programmer(); Person programmerProxy = (Person)Proxy.newProxyInstance( ProxTest.class.getClassLoader(), p.getClass().getInterfaces(), new MyInvocationHandler(p)); System.out.println("动态代理类的父类:" + programmerProxy.getClass().getSuperclass().getName()); String mes = programmerProxy.play(); System.out.println(mes); } }
控制台打印:
动态代理类的父类:java.lang.reflect.Proxy
before------------
com.sun.proxy.$Proxy0
after----------------------
调用娱乐方法
3. 底层实现原理
1. 如下源码:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /* * Look up or generate the designated proxy class. */ Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } 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); } }
2. 源码解析
Proxy.newProxyInstance产生代理类对象,这个方法做了两件重要的事情,首先生成实现传入接口的实现类,然后通过反射创建对象,创建对象时传入一个参数,即我们自己实现的MyInvocationHandler
3. 具体运行情况
当运行代理对象的方法时,虚拟机做如下处理:
1.收集三个参数:代理对象的引用,当前调用方法的方法名,方法的参数
2.调用MyInvocationHandler的invoke方法,参数为上一步收集的参数
4. 实际应用
1. 日志,事务管理
2. 远程过程调用RPC,远程调用时,具体实现在服务端,这时我们在invoke中实现通信即可(调用方法时,让远端的方法被调用,将结果发挥即可),这一切都是通过invoke中的socket通信实现的
啰嗦一下:
通过动态代理可以轻松地对一个类进行方法增强,改造,自定义