Spring的AOP,Struts2的拦截器,都是java动态代理实现的例子。
一、前言
定义
按照代理的创建时期,代理类可以分为两种。
- 静态代理
由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件已经存在。 - 动态代理
在程序运行时,运用反射机制动态创建而成。
动态代理分类
代理类型 | 实现方式 | 效率特点 | 应用前提 |
---|---|---|---|
jdk动态代理 | java反射机制 | 在生成类的过程中高效 | 目标类基于统一的接口 |
cglib动态代理 | asm | 在生成类之后的相关执行过程比较高效 |
关于ASM
ASM是一个java字节码操控框架。
- 能以二进制的形式修改已有类或动态生成类
- 直接产生二进制class文件
- 可以在类被加载入虚拟机之前动态改变类行为
- -
使用动态代理要先了解的类和接口
- Proxy 类
方法 | 用法 |
---|---|
static InvocationHandler getInvocationHandler(Object proxy) | 获取指定代理对象所关联的调用处理器 |
static Class getProxyClass(ClassLoader loader, Class[] interfaces) | 获取关联于指定类装载器和一组接口的动态代理类的类对象 |
static boolean isProxyClass(Class cl) | 判断指定类对象是否是一个动态代理类 |
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) | 为指定类装载器、一组接口及调用处理器生成动态代理类实例 |
2. InvocationHandler接口
Object invoke(Object proxy, Method method, Object[] args)
集中处理动态代理类上的所有方法调用。
第一个参数既是代理类实例,第二个参数是被调用的方法对象,第三个方法是调用参数。
调用处理器根据这三个参数进行预处理或分派到委托类实例上发射执行。
二、jdk动态代理
jdk通过 java.lang.reflect.Proxy 包来实现动态代理,创建机制是通过接口。
当RealObject创建一个对象时,jdk会进行一下步骤:
- 获取RealObject上的所有接口
- 确定要生成的代理类的类名Proxy
- 确定要实现的接口信息,在程序运行时动态创建该代理类Proxy的字节码
- 根据字节码转化为对应的class对象
- 创建InvocationHandler的实例handler,用来处理Proxy所有方法调用
- Proxy的class对象以创建的handler对象为参数,实例化一个Proxy对象
jdk的动态代理中,某个类必须有实现的接口,而生成的代理类也只能代理该类接口定义的方法。如果该类没有实现接口,那么这个类就不能同JDK产生动态代理了。
三、cglib动态代理
cglib实现动态代理的过程:
- 查找类上所有非final的public类型的方法定义
- 将这些方法的定义转化成字节码
- 将组成的字节码转换成class对象
- 实现MethodInterceptor接口,用来处理对代理类上所有方法的请求