码迷,mamicode.com
首页 > 其他好文 > 详细

JDK动态代理源码分析

时间:2020-07-28 16:57:12      阅读:58      评论:0      收藏:0      [点我收藏+]

标签:extends   验证   The   ble   time   oid   reflect   加载   factory   

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动态代理源码分析

标签:extends   验证   The   ble   time   oid   reflect   加载   factory   

原文地址:https://www.cnblogs.com/nicori/p/13386257.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!