深入理解JDK动态代理,代理模式

        本章以理论 + 实践来帮助你理解代理模式,JDK动态代理的实现方式。通俗易通,希望给各位一点小小的帮助

        阅读本章前需要小伙伴们了解Java面向对象,反射的基本知识,没有学习过的小伙伴先去学习吧~~

先来谈谈什么是代理模式

        假设这样一个场景,你的公司是一家软件公司,你是一位软件工程师。客户带着需求去找公司显然不会直接和你谈,而是去找商务谈,此时客户认为商务就代表公司。

        让我们用一张图来表示代理模式的含义:

        

         显然客户是通过商务去访问软件工程师的,那么商务(代理对象)存在的意义是什么呢?

        商务可以进行谈判,比如项目启动前的商务谈判,软件的价格、交付、进度的时间节点等,或者项目完成后的商务追讨应收账款等。商务也有可能在开发软件之前谈判失败,此时商务就会根据公司规则去结束和客户的合作关系,这些都不用软件工程师处理。因此,代理的作用就是,在真实对象访问之前或者之后加入对应的逻辑,或者根据其他规则决定要不要执行真实对象的方法,显然在这个例子里商务控制了客户和软件工程师的访问

        经过上面的论述,我们知道商务和软件工程师是代理和被代理的关系,客户是通过商务访问软件工程师的。此时客户就是调用者,商务就是代理对象,软件工程师就是真实对象。

        我们需要在调用者之前产生一个代理对象,而这个代理对象需要和真实对象建立代理关系,所以代理必须分为两个步骤:

  •     代理对象和真实对象建立关系
  •     实现代理对象的代理逻辑方法

        在Java中有多种动态代理技术,如JDK、CGLIB、Javassist、ASM,其中最常用的就是JDK动态代理,这是本章讨论的主要内容。注意:JDK动态代理必须借助接口才能产生代理对象,至于原因,在本章中不作讨论,有兴趣和自行研究。

JDK动态代理具体实现

1.  因为JDK动态代理需要真实对象实现接口,所以在这里定义接口

public interface HelloWorld {
    public void sayHello();
}

2.然后提供实现类HelloWorldImpl

public class HelloWorldImpl implements HelloWorld{
    @Override
    public void sayHello() {
        System.out.println("Hello World~~");
    }
}

        这是最简单的Java接口和实现类的关系,此时可以开始动态代理了。按照我们之前的分析,先要建立起代理对象和真实服务对象的关系,然后实现代理逻辑,所以一共分为两个步骤。

3.创建代理对象,绑定代理对象与真实对象的关系

        在JDK动态代理中,要实现代理逻辑类必须去实现java.lang.reflect.InvocationHandler接口,

它里面定义了一个invoke()方法,并提供接口数组用语下挂代理对象。下面为代理类的代码。

public class JdkProxyExample implements InvocationHandler {
    //真实对象
    private Object target;

    /**
     * 建立代理对象和真实对象的代理关系方法,并返回代理对象
     * @param target 真实对象
     * @return 代理对象
     */
    public Object bing(Object target){
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }

    /**
     * 
     * @param proxy 代理对象
     *
     * @param method 当前调度方法
     * @param args 当前方法参数
     * @return 代理结果返回
     * @throws Throwable 异常
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("进入代理逻辑方法");
        System.out.println("在调度真实对象之前的服务");
        Object obj = method.invoke(target, args);//相当于调用sayHello方法
        
        System.out.println("在调度真实对象后的方法");
        return obj;
    }

        第一步建立代理与被代理对象的关系,这里使用bind方法去完成的,方法里面首先用类的属性target保存了真实对象,然后通过如下代码建立并生成代理对象

      Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);

        其中newInstance包含了三个参数。

  • 第一个是类加载器,我们采用了target本身的类加载器
  • 第二个是把生成的动态代理对象下挂在哪些接口下,这个写法就是放在target实现的接口下。HelloWorldImpl对象的接口显然就是HelloWorld,代理对象可以这样声明;HelloWorld proxy = xxxx;。
  • 第三个是定义实现方法逻辑的代理类,this表示当前对象,它必须实现InvocationHandler接口的Invoke方法,它就是代理逻辑方法的现实方法

       第二步,实现代理逻辑方法。Invoke方法可以实现代理逻辑,Invoke方法的三个参数含义如下:

  • proxy 代理对象,就是bind方法生成的对象
  • method 当前调度的方法
  • args 调度方法的参数

    当我们使用代理对象调度方法后,它就会进入到invoke方法里

Object obj = method.invoke(target, args);

    这行代码相当于调度真实对象的方法,只是通过反射实现而已。

    类比前面的例子,proxy相当于商务对象,target相当于软件工程师对象,bing方法就是建立商务和软件工程师代理关系的方法。而invoke就是商务逻辑,它将控制软件工程师的访问。

测试JDK动态代理

@Test
    public void testJdkProxy(){
        JdkProxyExample jdkProxyExample = new JdkProxyExample();
        //绑定关系,因为挂在HelloWorld接口下,所以声明代理对象 HelloWorld proxy
        HelloWorld proxy = (HelloWorld) jdkProxyExample.bing(new HelloWorldImpl());
        //注意 此时HelloWorld对象已经是一个代理对象,它会进入代理的逻辑方法invoke
        proxy.sayHello();
    }
-------------------------------------------------------------------------------------------
结果:
进入代理逻辑方法
在调度真实对象之前的服务
Hello World~~
在调度真实对象后的方法

        首先通过bind方法绑定关系,然后在代理对象调度sayHello方法执行了代理的逻辑。

        这就是JDK动态代理,这是一种最常用的动态代理,十分重要。代理模式要掌握不容易,小伙伴们可以通过打断点,一步步验证执行 行的步骤,就一定能掌握好它~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值