代理模式简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。

代理模式的主要作用是扩展目标对象的功能,比如说在目标对象的某个方法执行前后你可以增加一些自定义的操作。

代理模式有静态代理和动态代理两种实现方式。

静态代理

静态代理实现步骤:

  1. 定义一个接口及其实现类;
  2. 创建一个代理类同样实现这个接口
  3. 将目标对象注入进代理类,然后在代理类的对应方法调用目标类中的对应方法。这样的话,我们就可以通过代理类屏蔽对目标对象的访问,并且可以在目标方法执行前后做一些自己想做的事情。

例如:小明想要打官司,则他需要找到代理律师来帮他

​ 代理律师负责将小明想说的话说出去,并在小明说话前面引用法律条文,在小明说话后发动道德谴责。

代码:

//说话的行为接口
interface Say{
    void sayMessage(String m);
}
//小明
class XiaoMing implements Say{
    @Override
    public void sayMessage(String m) {
        System.out.println("小明说出案情--by"+m);
    }
}

//静态代理 王律师
class LawyerWang implements Say{
    private final Say say;

    public LawyerWang(Say say) {
        this.say = say;
    }

    @Override
    public void sayMessage(String m) {
        System.out.println("引用法律条文");
        say.sayMessage(m);
        System.out.println("使用道德谴责");
    }
}

但是当又有一人来找王律师的时候,就需要重写代理的代码,非常不实用。


动态代理

相比于静态代理来说,动态代理更加灵活。我们不需要针对每个目标类都单独创建一个代理类,并且也不需要我们必须实现接口,我们可以直接代理实现类( CGLIB 动态代理机制)。

从 JVM 角度来说,动态代理是在运行时动态生成类字节码,并加载到 JVM 中的。

说到动态代理,Spring AOP、RPC 框架应该是两个不得不的提的,它们的实现都依赖了动态代理。

动态代理在我们日常开发中使用的相对较小,但是在框架中的几乎是必用的一门技术。学会了动态代理之后,对于我们理解和学习各种框架的原理也非常有帮助。

就 Java 来说,动态代理的实现方式有很多种,比如 JDK 动态代理CGLIB 动态代理等等。

JDK动态代理

介绍

在 Java 动态代理机制中 InvocationHandler 接口和 Proxy 类是核心。

  1. InvocationHandler接口

在使用动态代理时,我们需要定义一个位于代理类与委托类之间的中介类,这个中介类被要求实现InvocationHandler接口,这个接口的定义如下:

/**
 * 调用处理程序
 */
public interface InvocationHandler { 
    Object invoke(Object proxy, Method method, Object[] args); 
} 
复制代码

从InvocationHandler这个名称我们就可以知道,实现了这个接口的中介类用做“调用处理器”。

当我们调用代理类对象的方法时,这个“调用”会转送到invoke方法中。

代理类对象作为proxy参数传入,

参数method标识了我们具体调用的是代理类的哪个方法,

args为这个方法的参数。

这样一来,我们对代理类中的所有方法的调用都会变为对invoke的调用,这样我们可以在invoke方法中添加统一的处理逻辑(也可以根据method参数对不同的代理类方法做不同的处理)。因此我们只需在中介类的invoke方法实现中输出“before”,然后调用委托类的invoke方法,再输出“after”。
作者:Chaexsy
链接:https://juejin.cn/post/6844903591501627405
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  1. Proxy

Proxy 类中使用频率最高的方法是:newProxyInstance() ,这个方法主要用来生成一个代理对象。

    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        ......
    }Copy to clipboardErrorCopied

这个方法一共有 3 个参数:

  1. loader :类加载器,用于加载代理对象。
  2. interfaces : 被代理类实现的一些接口;
  3. h : 实现了 InvocationHandler 接口的对象;

接口和被代理(委托方)

//说话的行为接口
interface Say{
    void sayMessage(String m);
}
//小明
class XiaoMing implements Say{
    @Override
    public void sayMessage(String m) {
        System.out.println("小明说出案情--by"+m);
    }
}

中介类

对于XiaoMing这个类来说LawyerProxy类是他的代理,构成了静态代理

class LawyerProxy implements InvocationHandler{
    final private Object object;

    public LawyerProxy(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("引用法律条文");
        method.invoke(object,args);
        System.out.println("使用道德谴责");
        return null;
    }
}

实际调用

而对于LawyerProxy类来说,Proxy 类是它的代理,构成了静态代理

	//动态代理
  System.out.println("===动态代理===");
  LawyerProxy lawyerProxy = new LawyerProxy(new XiaoMing());
  Say s = (Say)Proxy.newProxyInstance(Say.class.getClassLoader(), new Class[]{Say.class}, lawyerProxy);
  s.sayMessage("动态代理类");

也就是说,动态代理关系由两组静态代理关系组成,这就是动态代理的原理