JDK动态代理源码分析
Posted nicori
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDK动态代理源码分析相关的知识,希望对你有一定的参考价值。
JDK动态代理源码分析
动态代理一般常用有两种实现方式:JDK和CGLIB
案例
public class DynamicProxyTestByJDK { public static void main(String[] args) { Buy buy = new BuyImpl(); Buy proxyBuy = (Buy)Proxy.newProxyInstance(Buy.class.getClassLoader(),new Class[] {Buy.class},new DynamicProxyHandler(buy)); proxyBuy.buy(); } }
代理类
public class DynamicProxyHandler implements InvocationHandler{ private Object object; public DynamicProxyHandler(final Object object) { this.object = object; } public Object invoke(Object proxy,Method method,Object[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { System.out.println("拿出钱包"); //调用BuyImpl.buy(); Object result = method.invoke(object,args); System.out.println("收起钱包"); return result; } }
源码分析
/* * ClassLoader 类加载器 * interfaces 接口类 * InvocationHandler 调用处理代码 */ @CallerSensitive public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException{ //判断代理类不为空 Objects.requireNonNull(h); //克隆出接口类 final Class<?>[] intfs = interfaces.clone(); //获取Java安全管理器 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); } }
在newProxyInstance调用getProxyClass0()时生成代理类文件
跟进代码到getProxyClass0() -> proxyClassCache.get() -> subKeyFactory.apply()发现实际调用到的是ProxyClassFactory的apply方法
1.JDK动态代理为什么必须针对接口?
通过反编译ProxyClassFactory生成的代理类我们发现
public final class $Proxy0 extends Proxy implements Buy{ //此处省略equals、toString、hashCode以及静态匿名块加载对应的方法 public final void doSomething() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } }
这个代理类自动继承了Proxy,因为Java规定不支持多继承,因此只能依靠实现接口。
以上是关于JDK动态代理源码分析的主要内容,如果未能解决你的问题,请参考以下文章