代理模式、Java动态代理实现、原理解析

一、 代理模式

举例了一个场景,一个人A想追一个妹子C,可是A不认识C,而正好他的好朋友B认识C,A便托B去给C送花送礼物之类的,B就是A的代理为C服务。
大话设计模式的解释是:为其他对象提供一种代理以控制对这个对象的访问。 在这里插入图片描述
代理模式也是常用的java设计模式,特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等,委托类负责具体的实现。

二、 Java代理实现

1、静态代理简单实现

根据上面代理模式的类图,来写一个简单的静态代理的例子。我这儿举一个比较粗糙的例子:
一个人A想追一个妹子C,可是A不认识C,而正好他的好朋友B认识C,A便托B去给C送花,B就是A的代理为C服务。
首先,我们创建一个IGift接口。这个接口就是A(被代理类),和B(代理类)的公共接口,他们都有送礼物的方法。这样,A送的礼物就可以让B来代理执行。
IGift接口

package com.yangpeng.thread.Java代理;
/**
 * 代理类与委托类有同样的接口
 */
public interface IGift {
    /**
     * 送花
     */
    void sendFlowers();
}

A类实现IGift接口。A可以具体实施送花的实现。

package com.yangpeng.thread.Java代理;
/**
 * 委托类-具体的实现
 */
public class A implements IGift{

    @Override
    public void sendFlowers(){
        System.out.println("送给C一束玫瑰花");
    }
}

BProxy类,这个类也实现了IGift接口,但是还和A对象有关系。由于实现了IGift接口,同时持有一个A对象,那么B可以代理A对象执行送花给C行为。

package com.yangpeng.thread.Java代理;
/**
 * 代理类,和委托类存在关联关系
 * A代理类,也实现了IGift接口,保存一个A实体,这样既可以代理A产生行为
 */
public class BProxy implements IGift{
    //被代理的A
    public A a;
    public BProxy(IGift a) {
        if(a.getClass() == A.class)
        this.a = (A)a;
    }

    //代理送花,调用被代理A送花的行为
    @Override
    public void sendFlowers(){
        System.out.println(a.getName()+"让我送的。");
        a.sendFlowers();
    }
}

使用代理模式:

package com.yangpeng.thread.Java代理;

public class Demo {
    public static void main(String[] args) {
        //被代理对象:A先生
        IGift A = new A("A先生");
        //代理对象B,并将A代理给B
        IGift B = new BProxy(A);
        //B代理送花给C,并告诉C是A送的
        B.sendFlowers();
    }
}

运行结果:
在这里插入图片描述
总结:
这里并没有直接通过A(被代理对象)来执行送花给C的行为,而是通过B(代理对象)来代理执行了。这就是代理模式。

代理模式最主要的就是有一个公共接口(IGift),一个具体的类(A),一个代理类(BProxy),代理类持有具体类的实例,代为执行具体类实例方法。代理模式在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途。这里的间接性就是指不直接调用实际对象的方法,那么我们在代理过程中就可以加上一些其他用途。就这个例子来说,加入B在帮A送花之前想要先反映一下是谁送的话,通过代理模式很轻松就能办到。
在这里插入图片描述

2、动态代理简单实现

定义:代理类在程序运行时创建的代理方式被成为动态代理。
优点:相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。
使用:在java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过这个类和这个接口可以生成JDK动态代理类和动态代理对象。

  1. 创建一个InvocationHandler对象
 //创建一个与代理对象相关联的InvocationHandler
 InvocationHandler giftMyInvocationHandler = new MyInvocationHandler<IGift>(A);
package com.yangpeng.thread.Java代理;

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

public class MyInvocationHandler<T> implements InvocationHandler {
   //invocationHandler持有的被代理对象
   T target;
   public MyInvocationHandler(T target){
       this.target = target;
   }

   /**
    * proxy:代表动态代理对象
    * method:代表正在执行的方法
    * args:代表调用目标方法时传入的实参
    */
   @Override
   public Object invoke(Object proxy, Method method, Object[] args)
           throws Throwable{
       //代理过程中插入个性化打印
       System.out.println("代理执行" +method.getName() + "方法");
       Object result = method.invoke(target, args);
       return result;
   }
}
  1. 使用Proxy类的getProxyClass静态方法生成一个动态代理类BProxyClass
Class<?> bProxyClass = Proxy.getProxyClass(IGift.class.getClassLoader(),new Class<?>[]{IGift.class});
  1. 获得stuProxyClass 中一个带InvocationHandler参数的构造器constructor
Constructor<?> constructor = bProxyClass.getConstructor(InvocationHandler.class);
  1. 通过构造器constructor来创建一个动态实例BProxy
IGift bProxy = (IGift) constructor.newInstance(new Object[]{giftMyInvocationHandler});

完整代码:


import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class Demo {
   public static void main(String[] args) throws Exception{
       //1、被代理对象:A先生
       IGift A = new A("A先生");
       //2、创建一个InvocationHandler对象
       //创建一个与代理对象相关联的InvocationHandler
       InvocationHandler giftMyInvocationHandler = new MyInvocationHandler<IGift>(A);
       //3、使用Proxy类的getProxyClass静态方法生成一个动态代理类bProxyClass
       Class<?> bProxyClass = Proxy.getProxyClass(IGift.class.getClassLoader(),new Class<?>[]{IGift.class});
       //4、获得cbProxyClass中一个带InvocationHandler参数的构造器constructor
       Constructor<?> constructor = bProxyClass.getConstructor(InvocationHandler.class);
       //5、创建一个代理对象 bProxy来代理A,代理对象的每个执行方法都会替换执行Invocation中的invoke方法
       IGift bProxy = (IGift) constructor.newInstance(new Object[]{giftMyInvocationHandler});
       //6、B代理执行送花
       bProxy.sendFlowers();
   }
}

一个动态代理对象就创建完毕,上面四个步骤可以通过Proxy类的newProxyInstances方法来简化:

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

public class Demo {
    public static void main(String[] args) throws Exception{
        IGift A = new A("A先生");
        InvocationHandler giftMyInvocationHandler = new MyInvocationHandler<IGift>(A);
        IGift bProxy = (IGift) Proxy.newProxyInstance(IGift.class.getClassLoader(),new Class<?>[]{IGift.class},giftMyInvocationHandler);
        bProxy.sendFlowers();
    }
}

3、动态代理根据源码解析原理

上面我们利用Proxy类的newProxyInstance方法创建了一个动态代理对象,查看该方法的源码如下:

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);
		
        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
         //TODO getProxyClass静态方法生成一个动态代理类
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
			//TODO 获得cbProxyClass中一个带InvocationHandler参数的构造器constructor
            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;
                    }
                });
            }
            //TODO·创建一个代理对象
            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);
        }
    }

其中,我们最应该关注的是 Class<?> cl = getProxyClass0(loader, intfs);这句,这里产生了代理类,后面代码中的构造器也是通过这里产生的类来获得,可以看出,这个类的产生就是整个动态代理的关键,由于是动态生成的类文件,我这里不具体进入分析如何产生的这个类文件,只需要知道这个类文件时缓存在java虚拟机中的,我们可以通过下面的方法将其打印到文件里面,一睹真容:

public class Test {
    public static void main(String[] args) throws Exception{
        byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", IGift.class.getInterfaces());
        String path = "D:\\学习\\bProxy.class";
        try(FileOutputStream fos = new FileOutputStream(path)) {
            fos.write(classFile);
            fos.flush();
        } catch (Exception e) {
            System.out.println("写文件错误");
        }

    }
}

对bProxy.class文件进行反编译如下:

import com.yangpeng.thread.Java代理.IGift;
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 IGift
{
  private static Method m1;
  private static Method m3;
  private static Method m2;
  private static Method m0;
/**
  *注意这里是生成代理类的构造方法,方法参数为InvocationHandler类型,看到这,是不是就有点明白
  *为何代理对象调用方法都是执行InvocationHandler中的invoke方法,而InvocationHandler又持有一个
  *被代理对象的实例,不禁会想难道是....? 没错,就是你想的那样。
  *
  *super(paramInvocationHandler),是调用父类Proxy的构造方法。
  *父类持有:protected InvocationHandler h;
  *Proxy构造方法:
  *    protected Proxy(InvocationHandler h) {
  *         Objects.requireNonNull(h);
  *         this.h = h;
  *     }
  *
  */
  public $Proxy0(InvocationHandler paramInvocationHandler)
    throws 
  {
    super(paramInvocationHandler);
  }

  public final boolean equals(Object paramObject)
    throws 
  {
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
/**
  * 
  *这里调用代理对象的sendFlowers方法,直接就调用了InvocationHandler中的invoke方法,并把m3传了进去。
  *this.h.invoke(this, m3, null);这里简单,明了。
  *来,再想想,代理对象持有一个InvocationHandler对象,InvocationHandler对象持有一个被代理的对象,
  *再联系到InvacationHandler中的invoke方法。嗯,就是这样。
  */
  public final void sendFlowers()
    throws 
  {
    try
    {
      this.h.invoke(this, m3, null);
      return;
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final String toString()
    throws 
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final int hashCode()
    throws 
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      //看看这儿静态块儿里面有什么,是不是找到了sendFlowers方法。请记住sendFlowers通过反射得到的名字m3,其他的先不管
      m3 = Class.forName("com.yangpeng.thread.Java代理.IGift").getMethod("sendFlowers", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}

jdk为我们的生成了一个叫$Proxy0(这个名字后面的0是编号,有多个代理类会一次递增)的代理类,这个类文件时放在内存中的,我们在创建代理对象时,就是通过反射获得这个类的构造方法,然后创建的代理实例。通过对这个生成的代理类源码的查看,我们很容易能看出,动态代理实现的具体过程。

我们可以对InvocationHandler看做一个中介类,中介类持有一个被代理对象,在invoke方法中调用了被代理对象的相应方法。通过聚合方式持有被代理对象的引用,把外部对invoke的调用最终都转为对被代理对象的调用。

代理类调用自己方法时,通过自身持有的中介类对象来调用中介类对象的invoke方法,从而达到代理执行被代理对象的方法。也就是说,动态代理通过中介类实现了具体的代理功能。
注意:
生成的代理类:$Proxy0 extends Proxy implements Person,我们看到代理类继承了Proxy类,所以也就决定了java动态代理只能对接口进行代理,Java的继承机制注定了这些动态代理类们无法实现对class的动态代理。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值