jdk动态代理的原理

 一、代理是什么

        代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

       通俗的讲,在有些情况下,一个客户不能或者不想直接访问另一个对象,这时需要找一个中介帮忙完成某项任务,这个中介就是代理对象。例如,购买火车票不一定要去火车站买,可以通过 携程或者淘宝上买。又比如,找保姆、找工作等都可以通过找58或boss等网站中介完成。

二、代理的实现

在java中代理实现的方式有两种,一种是通过继承的方式,另一种是通过组合的方式去实现。

1.继承模式

package com.example.demo.proxy;

public class HouseOwner {
    public void rent() {
        System.out.println("和房东签署协议,租房完成!");
    }
}
package com.example.demo.proxy;

public class Intermediary extends HouseOwner {
    public void rent() {
        System.out.println("找房....");
        super.rent();
        System.out.println("收房租....");
    }
}
package com.example.demo.proxy;

public class Test {
    public static void main(String[] args) {
        HouseOwner houseOwner = new Intermediary();
        houseOwner.rent();
    }
}

2.组合模式

组合模式有三个关键点:

  •  代理类和被代理类实现同一接口
  •  代理类持有被代理类的接口引用。
  •  代理类通过构造函数函数传入被代理类。
package com.example.demo.proxy;

public interface Owner {
    void rent();
}
package com.example.demo.proxy;

public class HouseOwner implements Owner {
    public void rent() {
        System.out.println("和房东签署协议,租房完成!");
    }
}
package com.example.demo.proxy;

public class Intermediary implements Owner {

    private Owner owner;

    public Intermediary(Owner owner) {
        this.owner = owner;
    }

    public void rent() {
        System.out.println("找房....");
        owner.rent();
        System.out.println("收房租....");
    }
}
package com.example.demo.proxy;

public class Test {
    public static void main(String[] args) {
        Owner owner = new Intermediary(new HouseOwner());
        owner.rent();
    }
}

三、jdk动态代理实现 

package com.example.demo.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class Intermediary implements InvocationHandler {

    private Owner target;
    
    public Intermediary(Owner target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("找房....");
        //通过反射执行目标方法
        Object result = method.invoke(target, args);
        System.out.println("收房租....");
        return result;
    }
}
package com.example.demo.proxy;

import java.lang.reflect.Proxy;

public class Test {
    public static void main(String[] args) {
        HouseOwner houseOwner = new HouseOwner();
        Owner owner = (Owner) Proxy.newProxyInstance(houseOwner.getClass()
                .getClassLoader(), houseOwner.getClass()
                .getInterfaces(), new Intermediary(houseOwner));
        owner.rent();
    }
}

四、jdk动态代理实现原理

        jdk动态代理的实现与上面讲的组合模式实现代理基本一样,只不过不是在编译前手动编写的代理类,而是在运行时通过反射的方式,动态的生成了代理类,所以称为动态代理。

        核心实现源码:


package java.lang.reflect;

import java.lang.ref.WeakReference;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Arrays;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.BiFunction;
import sun.misc.ProxyGenerator;
import sun.misc.VM;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
import sun.reflect.misc.ReflectUtil;
import sun.security.util.SecurityConstants;


public class Proxy implements java.io.Serializable {

    private static final long serialVersionUID = -2222568056686623797L;

  
    private Proxy() {
    }

    protected Proxy(InvocationHandler h) {
        Objects.requireNonNull(h);
        this.h = h;
    }

   @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException{
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();
        
      
        Class<?> cl = getProxyClass0(loader, intfs);

       
        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方法,jdk在运行时动态生成了代理类$proxy0,并加载到了虚拟机中,这个类实际是不存在的。

        $proxy0类的代码如下:


package com.example.demo.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements Owner {
    private static Method method;

    static {
        try {
            method = Class.forName("com.example.demo.proxy.Owner").getMethod("rent");
        } catch (NoSuchMethodException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public $Proxy0(InvocationHandler invocationHandler) {
        super(invocationHandler);
    }

    public final void rent() {

        try {
            super.h.invoke(this, method, new Object[]{});
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }

    }
}

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不才不才不不才

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值