动态代理转载

原创
小哥 3年前 (2022-10-27) 阅读数 47 #大杂烩

让我们来比较一下Java的 classinterface 的区别:

  • 可以实例化 class (非 abstract );
  • 无法实例化 interface

所有 interface 类型的变量始终向上转换并指向一个实例:

CharSequence cs = new StringBuilder();

有没有可能不编写实现类而直接在运行时创建实现类? interface 那么这个实例呢?

这是可能的,因为Java标准库提供了一个动态代理(Dynamic Proxy)机制:您可以动态创建 interface 的实例。

什么是运行时动态创建?这听起来很复杂。所谓的动态动因对应于静态。让我们来看看静态代码是如何编写的:

定义接口:

public interface Hello {
    void morning(String name);
}

编写实现类:

public class HelloWorld implements Hello {
    public void morning(String name) {
        System.out.println("Good morning, " + name);
    }
}

创建实例,转换为接口,调用:

Hello hello = new HelloWorld();
hello.morning("Bob");

这是我们通常编写代码的方式。

另一种方式是动态代码,我们仍然首先定义接口。 Hello ,但我们不编写实现类,而是直接通过。JDK提供了一个 Proxy.newProxyInstance() 创建了一个 Hello 接口对象。这种不实现类但在运行时动态创建接口对象的方式称为动态代码。JDK提供的动态创建接口对象的方法称为动态代理。

最简单的动态代理实现之一如下:

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

Run

动态创建一个 interface 示例如下:

  1. 定义一个 InvocationHandler 实例,负责实现接口的方法调用;
  2. 通过 Proxy.newProxyInstance() 创建 interface 实例,它需要3个参数:
    1. 使用的 ClassLoader 通常是接口类。 ClassLoader
    2. 要实现的接口数组需要至少传入一个接口;
    3. 用于处理接口方法调用。 InvocationHandler 实例。
  3. 将返回的 Object 强制转换为接口。

动态代理实际上是JDK在运行时动态创建class字节码和加载进程,它没有任何黑魔法,上面的动态代理重写静态实现类大概就这么长:

public class HelloDynamicProxy implements Hello {
    InvocationHandler handler;
    public HelloDynamicProxy(InvocationHandler handler) {
        this.handler = handler;
    }
    public void morning(String name) {
        handler.invoke(
           this,
           Hello.class.getMethod("morning"),
           new Object[] { name });
    }
}

其实就是JDK帮我们自动写一个上面的类(不需要源代码,可以直接生成字节码),没有黑魔法可以直接实例化接口。

小结

Java标准库提供了动态代理功能,允许动态创建一个接口的实例;

制作了动态代理 Proxy 创建一个代理对象,然后“代理”接口方法。 InvocationHandler 完成的。

地址: https://www.liaoxuefeng.com/wiki/1252599548343744/1264804593397984

版权声明

所有资源都来源于爬虫采集,如有侵权请联系我们,我们将立即删除

热门