spring源码分析一:动态代理
Jdk动态代理
只有接口无实现类动态代理: 参考Mybatis中MapperProxy类, 用于动态代理Mapper接口
public class Test { //需要动态代理的接口类 interface DaynamicInteface { int getInt(); String getString(); } public static void main(String[] args) throws InterruptedException { //动态代理实例化接口 DaynamicInteface daynamicInteface = (DaynamicInteface)Proxy.newProxyInstance(DaynamicInteface.class.getClassLoader(), new Class[]{DaynamicInteface.class}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //实现方法getInt if (method.getName().equals("getInt")){ System.out.println(111); return 1; } //实现方法getString else if (method.getName().equals("getString")){ System.out.println("aaa"); return "a"; } //java Objec默认方法实现 不实现会报错 else { return invokeDefaultMethod(proxy, method, args); } } }); //执行自定义方法 daynamicInteface.getString(); //执行object默认方法 daynamicInteface.toString(); } public static Object invokeDefaultMethod(Object proxy, Method method, Object[] args) throws Throwable { final Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class .getDeclaredConstructor(Class.class, int.class); if (!constructor.isAccessible()) { constructor.setAccessible(true); } final Class<?> declaringClass = method.getDeclaringClass(); return constructor.newInstance(declaringClass, MethodHandles.Lookup.PRIVATE) .unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args); } }
有接有实现类动态代理:常用于不修改代码的情况下 实现功能修改或者织入额外代码
/** 这是一个额外打印日志的动态代理 */ public class Test { //需要动态代理的接口类 interface DaynamicInteface { int getInt(); String getString(); } public static class DaynamicImpl implements DaynamicInteface{ @Override public int getInt() { System.out.println("执行了getInt"); return 0; } @Override public String getString() { System.out.println("执行了getString"); return null; } } public static void main(String[] args) throws InterruptedException { //原来的实现类实例化 DaynamicInteface target = new DaynamicImpl(); //代理类 在执行方法执行打印额外日志 DaynamicInteface proxy = (DaynamicInteface)Proxy.newProxyInstance(DaynamicInteface.class.getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //打印额外日志 if (method.getName().equals("getInt")){ System.out.println("我打印了日志:getInt"); } //打印额外日志 else if (method.getName().equals("getString")){ System.out.println("我打印了日志:getString"); } return method.invoke(target, args); } }); //执行自定义方法 proxy.getString(); //执行object默认方法 proxy.toString(); } } 结果: 我打印了日志:getString 执行了getString
Cglib动态代理:通常用于没有接口的情况使用
public class Test { public static class DaynamicImpl{ public int getInt() { System.out.println("执行了getInt"); return 0; } public String getString() { System.out.println("执行了getString"); return null; } } public static void main(String[] args) throws InterruptedException { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(DaynamicImpl.class); //设置回调函数 enhancer.setCallback(new MethodInterceptor(){ @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { //打印额外日志 if (method.getName().equals("getInt")){ System.out.println("我打印了日志:getInt"); } //打印额外日志 else if (method.getName().equals("getString")){ System.out.println("我打印了日志:getString"); } Object object = proxy.invokeSuper(obj, args); return object; } }); //这里的creat方法就是正式创建代理类(实际为目标类的子类) 因为系统环境参数设置了反编译文件存储路径 此时会讲实际的反编译文件写入D:\\java DaynamicImpl proxyImpl = (DaynamicImpl)enhancer.create(); proxyImpl.getInt(); proxyImpl.getString(); } } 结果: CGLIB debugging enabled, writing to 'D:\java' 我打印了日志:getInt 执行了getInt 我打印了日志:getString 执行了getString
区别:
JDK动态代理方式: 利用拦截器(拦截器必须实现InvocationHanlder)加上反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
CGLIB动态代理方式: 生成一个目标类的子类, 编译到JVM中, 在使用的时候则是利用父类申明子类调用的方式