基于JDK的动态代理实现

前言

必须具备反射相关知识,Spring AOP、IOC都是基于动态代理实现的,如果要学习Spring源码最好学习下动态代理。

JDK 动态代理
代理设计模式的原理:

使用一个代理将对象包装起来,然后使用代理对象取代原始对象。任何对原始对象的调用都要经过代理对象代理。由代理对象决定是否以及何时将方法调用转到原对象上。

动态代理
  • 动态代理是指客户通过代理类来调用其他对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象。
  • 动态代理使用场景:
    • 调试
    • 远程方法调用
首先思考一下,实现动态代理,需要解决哪些问题?
  1. 如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象?
  2. 当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法a?
解决方案

java.lang.reflect反射包下有一个Proxy类,一个InvocationHandler接口是我们实现动态代理的核心。

1 . InvocationHandler

该接口中仅定义了一个方法:public Object invoke(Object obj, Method method, Object[] args),在使用时,第一个参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组,即被代理类数组。这个抽象方法在代理类中动态实现。

2 . Proxy

该类即为动态代理类,static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h),返回代理类的一个实例,返回后的代理类可以当作被代理类使用。

动态代理步骤
  1. 创建被代理类及接口(JDK代理是接口代理)
  2. 创建Handle类实现 InvocationHandler接口 ,重写invoke方法
  3. 通过Proxy的newProxyInstance()方法获取代理类对象
  4. 通过代理类对象调用被代理类的方法
代码实现

1.创建接口

/**
 * 人类接口
 *
 * @author junjun.lei
 * @create 2020-03-26 19:31
 */
public interface Human {
    /**
     * 获取人的信仰
     *
     * @return 返回信仰
     */
    String getBelief();

    /**
     * 吃东西
     *
     * @param food
     */
    void eat(String food);
}

2.被代理类实现该接口

/**
 * 被 代理类
 * @author junjun.lei
 * @create 2020-03-27 11:33
 */
public class SupperMan implements Human {
    @Override
    public String getBelief() {
        return "I believe i can fly";
    }

    @Override
    public void eat(String food) {
        System.out.println("吃" + food);
    }
}

  1. 创建Handle类实现 InvocationHandler接口 ,重写invoke方法,并通过Proxy类的newProxyInstance()方法获取代理类对象
/**
 * 代理类
 * 要想实现动态代理,需要解决的问题?
 * 问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象。
 * 问题二:当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法a。
 *
 * @author junjun.lei
 * @create 2020-03-27 12:38
 */
public class MyInvocationHandle implements InvocationHandler {

    /**
     * 被代理类对象
     */
    private Object obj;

    public MyInvocationHandle(Object obj){
        this.obj=obj;
    }

    /**
     * 动态获取代理类对象
     *
     * @return
     */
    public  Object getProxyInstance() {
        return Proxy.newProxyInstance(this.obj.getClass().getClassLoader(),this.obj.getClass().getInterfaces(),this);
    }

    /**
     * 动态的去调用被代理类中的同名方法
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object returnValue = method.invoke(this.obj, args);
        return returnValue;
    }
}

4.动态代理测试

/**
 * 动态代理测试
 * @author junjun.lei
 * @create 2020-03-27 13:08
 */
public class ProxyTest {
    @Test
    public void test01() {
        SupperMan supperMan=new SupperMan();
        MyInvocationHandle handle = new MyInvocationHandle(supperMan);
        Human proxyInstance = (Human)handle.getProxyInstance();
        String belief = proxyInstance.getBelief();
        System.out.println(belief);
        proxyInstance.eat("盖浇饭");
    }
}

5.执行结果

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值