模式的秘密-代理模式(2)-JDK动态代理

代理模式-动态代理

(1)java

(2)编程

 

代码实践动态代理:dom

第一步:被代理类的接口:ide

package com.JdkProxy; public interface Moveable { void move(); }

第二步:被代理类:post

package com.JdkProxy; import java.util.Random; public class Car implements Moveable { @Override public void move() { //实现开车
        try { Thread.sleep(new Random().nextInt(1000)); System.out.println("汽车行驶中...."); } catch (InterruptedException e) { e.printStackTrace(); } } }

第三步:代理类:实现接口:InvocationHandler,同时把被代理类对象接口传入构造方法,学习

重写的接口的invoke方法。测试

package com.JdkProxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class TimeHandler implements InvocationHandler { private Object target; public TimeHandler(Object target) { this.target=target; } /* * 参数: * proxy:被代理对象 * method:被代理对象方法 * arg:方法的参数 * 返回值: * Object 方法的返回值 * */ @Override public Object invoke(Object proxy, Method method, Object[] arg) throws Throwable { long starttime=System.currentTimeMillis(); System.out.println("汽车开始形式...."); method.invoke(target); long endtime=System.currentTimeMillis(); System.out.println("汽车结束行驶...汽车形式时间:"+(endtime-starttime)+"毫秒"); return null; } }

测试类中实现代理:this

使用Proxy类的newProxyInstance方法产生一个被代理类的实例,该实例能够看成被代理类使用接口(对应cls.getInterfaces())中声明过的方法。spa

package com.JdkProxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class Test { /*JDK动态代理测试类 * */
    public static void main(String[] args) { Car car=new Car(); //InvocationHandler是一个接口,接口中定义了一个方法invoke。要想实现JDK动态代理, //代理类必须继承这个接口
        InvocationHandler h=new TimeHandler(car);//         Class cls=car.getClass();//获取类对象,以便获取类加载器,以及获取类的接口
        
        /* * newProxyInstance返回代理类的实例,返回后的代理类能够看成被代理类使用 * (可以使用被代理类的接口中声明过的方法) * loader:类加载器 * interfaces:实现接口 * h:InvocationHandler * */ Moveable m=(Moveable) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), h); m.move(); } }

测试结果:设计

汽车开始形式.... 汽车行驶中.... 汽车结束行驶...汽车形式时间:863毫秒

 

代理模式-动态代理

因此动态代理是这样一种Class:

  • 他在运行时候产生了的Class
  • 该class须要实现一组interface
  • 使用动态代理类时,必须实现InvocationHandler接口

动态代理实现步骤

1,建立一个实现InvocationHandler的类,他必须实现Invoke方法

2,建立被代理的类以及接口

3,调用Proxy的静态方法,建立一个代理类:

newProxyInstance(ClassLoader,class[] interfaces,InvocationHandler  h)。

4,经过代理调用方法。

 

jdk动态代理只能实现了接口的类。

 

jdk动态代理理解:

看完这个例子,个人最大疑惑是,返回代理类实例,执行方法的时候,调用的是被代理类中含有的方法,那么咱们代理类中重写的invoke方法,并无调用,

那这个方法有什么用,可是真正执行被代理类里面的方法的时候,却好像又确实执行了invoke方法,那么到底时候用到了invoke这个方法呢

 

这里看了一下这篇博客的解释,稍微能理解一下这种动态代理的处理执行过程:https://juejin.im/post/5a99048a6fb9a028d5668e62。

在静态代理部分,咱们在代理类中传入了被代理对象。但是,使用newProxyInstance生成动态代理对象的时候,咱们竟然再也不须要传入被代理对象了
咱们传入了的实际对象是InvocationHandler实现类的实例,这看起来有点像生成了InvocationHandler的代理对象,
在动态生成的代理类的任意方法中都会间接调用InvocationHandler->invoke(proxy, method, args)方法。 其实的确是这样。TimeProxy真正代理的对象就是InvocationHandler,不过这里设计的巧妙之处在于,InvocationHandler是一个接口,
真正的实现由用户指定。另外,在每个方法执行的时候,invoke方法都会被调用 ,这个时候若是你须要对某个方法进行自定义逻辑处理,
能够根据method的特征信息进行判断分别处理

 

看完这段文字,再看这个方法的执行:

Car car=new Car(); InvocationHandler h=new TimeHandler(car); Class cls=car.getClass(); Moveable m=(Moveable) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), h);

总结步骤:

  • InvocationHandler:这个接口主要用于自定义代理逻辑处理
  • 为了完成对被代理对象的方法拦截,咱们须要在InvocationHandler对象中传入被代理对象实例。
  • Proxy->newProxyInstance用于生成代理对象。
  • newProxyInstance的三个参数:
  • 前两个参数与被代理类的Class有关(被代理类的类加载器,被代理类的接口)。
  • 最后一个参数传入代理类InvocationHandler的实例。

 

想象一下,到此为止,若是咱们还须要对其它任意对象进行代理,是否还须要改动newProxyInstance方法的源码,答案是:彻底不须要!

只要你在newProxyInstance方法中指定代理须要实现的接口指定用于自定义处理的InvocationHandler对象

整个代理的逻辑处理都在你自定义的InvocationHandler实现类中进行处理。

至此,而咱们终于能够从不断地写代理类用于实现自定义逻辑的重复工做中解放出来了,今后须要作什么,交给InvocationHandler。

 

答疑解惑

invoke方法的第一个参数proxy到底有什么做用?

1. 可使用反射获取代理对象的信息(也就是proxy.getClass().getName(),输出可得:com.sun.proxy.$Proxy0)。
2. 能够将代理对象返回以进行连续调用,这就是proxy存在的目的。由于this并非代理对象,指的是被代理对象实例(如例子中的car),

proxy指的是被代理对象。这个问题其实也好理解,若是你的接口中有方法须要返回自身,若是在invoke中没有传入这个参数,将致使实例没法正常返回。

在这种场景中,proxy的用途就表现出来了。简单来讲,这其实就是最近很是火的链式编程的一种应用实现。

动态代理到底有什么用?

学习任何一门技术,必定要问一问本身,这到底有什么用。其实,在这篇文章的讲解过程当中,咱们已经说出了它的主要用途。你发现没,使用动态代理咱们竟然能够在不改变源码的状况下,直接在方法中插入自定义逻辑。这有点不太符合咱们的一条线走到底的编程逻辑,这种编程模型有一个专业名称叫 AOP。所谓的AOP,就像刀同样,抓住时机,趁机插入。

相关文章
相关标签/搜索