Java 反射机制
很多编程语言都有“反射机制”。这项机制能让程序在运行期间 自省(introspect)。
通过这项技术,我们可以在运行期间获取类的属性、方法等元数据,甚至修改类的定义。
Java 的反射机制也一样。
AccessibleObject
AccesibleObject 是使用 Java 反射机制上通常会用到的类。
java.lang.reflect.Constructor、java.lang.reflect.Method、java.lang.reflect.Field 都继承自该类。
Java 9 之后,原则上只有被反射操作的模块和指定的包对反射调用者模块Open,才能使用 setAccessible(Jigsaw)。
所以虽然直接使用 setAccessible 的行为被兼容,但是存在争议。
动态代理
动态代理一种程序运行时动态构建代理、动态处理代理方法调用的机制。
AOP(面向切面编程)、RPC调用包装之类场景就用到了动态代理。
动态代理的实现方式有很多。Java的反射机制就是其中一种。 ASM、cglib、Javassist 都可以实现动态代理。
代理就是对调用目标的一个包装,类似设计模式里的代理模式。对目标代码的调用时通过代理对象完成的,而不是直接调用。
代理机制可以让 调用者 和 实现者 之间解耦;隐藏一些调用者不太关心的操作,提供更友好的访问方式。
JDK Proxy 实现动态代理
JDK Proxy 内部用到了 Java 反射机制 和 ASM。
它基于接口实现代理,即构建一个也实现了目标接口的类。
因为是基于接口的代理,代理对象的类型不是原类型,也不是原类型的子类,所以业务逻辑不能依赖于类继承关系。
这是一个利用 JDK Proxy 实现动态代理的样例。
示例代码中指定代理实例代理所有 HelloImpl 类实现的类:HelloImpl.class.getInterfaces()
如果只想代理 Hello 接口,可以指定为 new Class<?>[]{Hello.class}
MyInvocationHandler.invoke 方法内部调用了实际目标方法 HelloImpl.sayHello。
此处代理方法只是输出了一行日志。可根据需求实现各种逻辑(日志、用户鉴权、全局性异常处理、性能监控、事务处理等)。
这种“全包围”的代理方式类似于 AOP 中的“环绕通知”(如,AspectJ 中的 @Around)。
public class MyDynamicProxy { public static void main(String[] args) { HelloImpl hello = new HelloImpl(); MyInvocationHandler handler = new MyInvocationHandler(); // 构造代理类实例 Hello proxyHello = (Hello)Proxy.newProxyInstance( HelloImpl.class.getClassLoader(), HelloImpl.class.getInterfaces(), handler); // 调用代理方法 proxyHello.sayHello(); } interface Hello { void sayHello(); } class HelloImpl implements Hello { @Override public void sayHello() { System.out.println("Hello World"); } } class MyInvocationHandler implements InvocationHandler { private Object target; public MyInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Invoking sayHello"); Object result = method.invoke(target, args); return result; } } }
cglib 实现动态代理
当被代理类未实现接口,准确地说是被代理方法不属于某个接口时,我们可以用 cglib 来实现代理。
cglib 内部使用了 ASM。
它实现代理的原理是构建一个目标类的子类。与 JDK Proxy 基于接口的方式相比,该方式更近似使用被调用者本身。
Spring AOP 中也可显式指定使用 cglib。
JDK Proxy vs cglib
JDK Proxy 的优势
JDK Proxy 可最小化依赖关系。这可以简化开发与维护:
- 代码实现简单
- 可以随着JDK平滑升级
- JDK通常比 cglib 更可靠
cglib 的优势
-
不受“无接口”的限制
不过,面向接口编程依然是值得推荐的原则。这对解耦及提升可测性方面非常有效。
- 只操作业务所关心的类,不必增加处理其它相关类的工作量
-
高性能
其实 JDK Proxy 的性能也不差,在典型场景中近似 cglib
结论
与通常对待性能的技术选型一样,在没有明确的统计数据与需求前,不必纠结与选何种技术。
可靠性、可维护性、编程工作量都是主要的考虑因素。
相关推荐
Java的反射机制与动态代理是Java编程中两个非常重要的高级特性,它们允许程序在运行时检查和操作类、接口和对象。理解并熟练运用这两个概念能够极大地提高代码的灵活性和可扩展性。 **反射机制** Java反射机制是...
反射机制的核心在于Java提供的`java.lang.reflect`包,其中包括了`Class`、`Field`、`Method`、`Constructor`和`Array`等类,它们分别用于表示类、字段、方法、构造器和数组的相关信息。 1. **Class类**:每个类在...
总之,Java反射机制与动态代理为开发者提供了强大的灵活性,可以在运行时探索和修改程序行为,实现更复杂的设计模式和编程策略。然而,由于它们涉及底层操作,过度使用可能会影响程序性能和安全性,因此在实际应用中...
反射机制的核心在于能够在运行时动态地获取类的信息并进行操作,这为Java提供了高度的灵活性和动态性。 1. **Java反射机制的基本功能** - 获取类信息:通过`Class`类的`forName()`方法,可以得到运行时的类信息。 ...
Java反射机制与动态代理是Java编程中的重要概念,它们在软件设计中扮演着核心角色,尤其是在框架开发中。本文将深入探讨这两个主题,以及如何在实际应用中利用它们。 首先,我们来理解Java反射机制。反射是Java的一...
综上所述,Java反射机制与动态代理是Java开发中的高级特性,它们使得程序在运行时具有更高的灵活性和扩展性。掌握这两个概念对于理解Java的深层机制和开发复杂系统至关重要。同时,了解如何处理文件上传下载,尤其是...
Java编程语言以其强大的功能和广泛的应用领域而备受程序员喜爱,其中反射和代理是两个非常重要的概念,它们...对于Java学习者来说,这是一个非常有价值的资源,可以帮助你在实践中提升技能,加深对Java核心机制的理解。