Java 动态代理类是原始类之上的一种“附加组件”,它允许Java 开发人员根据需要更改原始类的行为。假设,如果您将一个类用作现成JAR 库的一部分,并且您不能简单地重写其源代码,但您还需要更改该类的行为方式。
例如,您不知道可以在您的对象上调用此类的哪个方法,但您想输出一个重要的“确认”消息。Java 动态代理是这个问题的理想解决方案。
在本文中,我们将了解有关 Java 动态代理的所有信息。什么是 Java 动态代理?他们是如何工作的?以及何时应该在您的 Java 代码中理想地使用它。
Java 动态代理是 Java 代理设计模式的一部分。当程序需要扩展或修改现有类的某些功能时,它允许创建代理对象。在这种情况下,将实例化代理对象而不是原始对象。通常,代理对象具有与原始对象相同的方法,并且在 Java 代理类中扩展了原始类。Java 动态代理模式具有原始对象的句柄,并且也可以调用原始类方法。
因此,代理类可以以非常方便的方式实现很多不同的东西,这样的事情很少有例子包括:
可以将日志记录方法扩展到原始类以记录方法何时启动和停止。
可以使用 Java 动态代理对参数执行额外的检查。
代理类也可用于在最终确定之前模拟原始类的行为,以检查它是否按预期执行。
如果不修改类的原始代码,就无法完成上述应用,这使得它们成为 Java 动态代理的理想应用。
在这样的应用程序中,代理类不直接在原始类对象上实现功能。遵循单一职责原则,代理类只创建一个代理,并在处理程序中修改实际行为。当调用代理对象而不是原始对象时,Java 动态代理将决定是否必须调用原始方法或处理程序。处理程序可以执行其扩展任务,也可以调用原始方法来执行原始任务。
它是 Java 编程语言中一个相对高级的主题,因为它需要一些广泛的 Java 知识。计划使用 Java 动态代理的开发人员必须了解反射类的使用或字节码操作或如何编译动态生成的 Java 代码。要创建字节码,首先应该学习如何使用 cglib 或 bytebuddy 或内置的 Java 编译器。
InvocationHandler 是一个特殊的接口,它允许我们拦截对对象的任何方法调用并添加我们需要的附加行为。我们首先需要通过创建一个实现此接口的类来创建我们的拦截器。它只包含一个方法:invoke(),其中原始对象作为参数传递,被代理。
当我们考虑代理类和它们调用的处理程序时,就会明白为什么责任分离在这里非常重要。代理类总是在运行时生成,但代理类调用的处理程序可以用源代码编码,并且可以在编译时与整个程序的代码一起编译。
代理类及其实例是使用 java.lang.reflect.Proxy 类的静态方法创建的。它是 JDK 的一部分,可以创建代理类或直接创建它的实例。Java 内置代理的使用相对容易一些。您需要做的就是实现一个 java.lang.InvocationHandler,以便代理对象稍后可以调用它。在此之后,调用来自 Invocation Handler 的 invoke() 方法。
另一个方法,Proxy.getProxyClass 方法返回一个代理类的 java.lang.Class 对象,给定一个类加载器和一个接口数组。
根据动态代理类 Java 文档,必须传递给 Proxy.getProxyClass 的参数有一些限制:
interfaces 数组中的所有 Class 对象都必须表示接口,而不是类或原始类型。
interfaces 数组中的两个元素不能引用相同的 Class 对象。
所有接口类型必须通过指定的类加载器按名称可见。
所有非公共接口必须在同一个包中;否则,代理类将不可能实现所有接口,无论它定义在什么包中。
对于具有相同签名的指定接口的任意数量的成员方法:
如果任何方法的返回类型是 void 或原始类型,则所有方法都必须具有相同的返回类型。
如果不是,则其中一个方法必须具有可以分配给所有方法的所有返回类型的返回类型。
生成的代理类不得超过虚拟机对类施加的任何限制。
下面的代码演示了在代码中使用 Java 动态代理的所有讨论点:
包代理;
导入java.lang.reflect.InvocationHandler;
导入java.lang.reflect.InvocationTargetException;
导入java.lang.reflect.Method;
导入java.lang.reflect.Proxy;
公共类 ProxyDemo {
接口如果{
void originalMethod(String str);
}
静态类原始实现If {
public void originalMethod(String str) {
System.out.println(str);
}
}
静态类Handler实现InvocationHandler {
private final If original;
public Handler(如果是原始的) {
this.original = 原创;
}
public Object invoke(Object proxy, Method method, Object[] args)
抛出 IllegalAccessException、IllegalArgumentException、
调用目标异常{
System.out.println("代理前:");
method.invoke(原始, args);
System.out.println("代理后:");
返回空值;
}
}
public static void main(String[] args){
原始原始=新原始();
处理程序处理程序=新处理程序(原始);
If a = (If) Proxy.newProxyInstance(If.class.getClassLoader(),
新类[] { If.class },
处理程序);
a.originalMethod("你好");
}
}
现在,如果处理程序想要调用原始对象的原始方法,首先,它必须有权访问它。这不会由 Java 代理实现提供。开发人员必须在代码中手动将此参数传递给处理程序实例。
您一定已经注意到,通常将一个名为“proxy”的对象作为参数传递给调用处理程序。这是由 Java 反射动态生成的代理对象,而不是我们要代理的对象。因此,开发人员为每个原始类使用单独的处理程序对象,或者他们也可以使用一些共享对象,如果有任何方法可以调用,他们也可以知道要调用哪个原始对象。您还可以创建一个调用处理程序和一个没有任何原始对象的接口的代理。您不需要任何类来实现代码中的接口。动态创建的代理类会自动实现接口。
Java 动态代理在流行技术中被积极使用。在安全框架中可以看到一种常见的用法。
它用于在授权人员应该使用的所有方法中添加安全检查。使用 Java 动态代理,可以添加安全检查,导致用户输入有效凭据,而无需复制验证码来访问每个方法。
它还可以用于为方法创建日志。这也很容易通过使用代理类来实现。您可以简单地向原始方法添加额外的代码,以在最后显示完整的日志。
以上就是关于“Java动态代理的简介”,大家如果想了解更多相关知识,不妨来关注一下极悦Java视频教程,里面的课程内容从入门到精通,细致全面,通俗易懂,很适合没有基础的小伙伴学习,希望对大家能够有所帮助。
你适合学Java吗?4大专业测评方法
代码逻辑 吸收能力 技术学习能力 综合素质
先测评确定适合在学习