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动态代理源码分析的主要内容,如果未能解决你的问题,请参考以下文章

JDK动态代理[2]----JDK动态代理的底层实现之Proxy源码分析

JDK动态代理源码分析

JDK动态代理源码分析

设计模式3.2-- JDK动态代理源码分析有多香?

源码分析:Spring是如何跟JDK动态代理结合

源码分析:Spring是如何跟JDK动态代理结合