Java反射机制与动态代理
Java 反射机制
**反射概念:**在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
反射机制是 Java 语言提供的一种基础功能,赋予程序在运行时自省(introspect,官方用语)的能力。通过反射我们可以直接操作类或者对象,比如获取某个对象的类定义,获取类声明的属性和方法,调用方法或者构造对象,甚至可以运行时修改类定义。
获取Class对象的三种方式:
- 通过Object类
getClass()
方法 - 通过一个静态的
class
属性获取 - 通过Class类的静态方法:
forName(String className)
——常用
Java 动态代理
动态代理是一种方便运行时动态构建代理、动态处理代理方法调用的机制,很多场景都是利用类似机制做到的,比如用来包装 RPC 调用、面向切面的编程(AOP)。
实现动态代理的方式很多,比如 JDK 自身提供的动态代理,就是主要利用了上面提到的反射机制。还有其他的实现方式,比如利用传说中更高性能的字节码操作机制,类似 ASM、cglib(基于 ASM)、Javassist 等。
JDK动态代理的实现与原理
实现:
- 创建一个与代理对象相关联的
InvocationHandler
- 使用
Proxy
类的getProxyClass
静态方法生成一个动态代理类ProxyClass
- 获得
ProxyClass
中一个带InvocationHandler
参数的构造器constructor- 通过构造器constructor来创建一个动态实例Proxy
原理:
jdk为我们的生成了一个叫$Proxy0(这个名字后面的0是编号,有多个代理类会一次递增)的代理类,这个类文件时放在内存中的,我们在创建代理对象时,就是通过反射获得这个类的构造方法,然后创建的代理实例。我们可以对
InvocationHandler
看做一个中介类,中介类持有一个被代理对象,在invoke
方法中调用了被代理对象的相应方法。通过聚合方式持有被代理对象的引用,把外部对invoke
的调用最终都转为对被代理对象的调用。代理类调用自己方法时,通过自身持有的中介类对象来调用中介类对象的invoke方法,从而达到代理执行被代理对象的方法。【动态代理通过中介类实现了具体的代理功能】
CGLIB动态代理与JDK动态区别
-
java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvocationHandler【增强器】来处理。
-
cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
-
JDK动态代理只能对实现了接口的类生成代理,而不能针对类 。 CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 。 因为是继承,所以该类或方法最好不要声明成final ,final可以阻止继承和多态。
1.JDK动态代理是实现了被代理对象的接口,Cglib是继承了被代理对象。
2.JDK和Cglib都是在运行期生成字节码,JDK是直接写Class字节码,Cglib使用ASM框架写Class字节码,Cglib代理实现更复杂,生成代理类比JDK效率低。
3.JDK调用代理方法,是通过反射机制调用,Cglib是通过FastClass机制直接调用方法,Cglib执行效率更高。
JDK动态代理的实例
本示例以交班费为实例,各个学生上交班费由班长进行代理上交,同时班长在统一上交时,可以作其他的操作。本例班长工具类作了计算上交过程的时间消耗的功能增强。
- Person 接口
1 | public interface Person { |
- Student对象类
1 | public class Student implements Person { |
- 班长工具类
1 | public class MonitorUtil { |
- 代理类
1 | import java.lang.reflect.InvocationHandler; |
- 测试类
1 | import java.lang.reflect.InvocationHandler; |