• JDK动态代理源码分析


    JDK动态代理源码分析

    动态代理一般常用有两种实现方式:JDK动态代理和CGLIB

    JDK是通过反射生成一个实现代理接口的匿名类,调用InvocationHandler来处理。

    案例

    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规定不支持多继承,因此只能依靠实现接口。

  • 相关阅读:
    免密码输入ssh连接
    关于调用函数使用栈
    uos中tftp、nfs服务重启方法、路径
    uos安装dogtail首次打开提示可访问性,点击确定按钮如何自动化
    linux查看启动项
    5.gitlab提交时触发jenkins
    Fun blog
    Github Page 加速 | vercel ~~
    98--RocketMQ原生API收发消息
    97--RocketMQ工作原理
  • 原文地址:https://www.cnblogs.com/nicori/p/13386257.html
Copyright © 2020-2023  润新知