JDK动态代理
在JDK1.3以后提供了动态代理的技术,允许开发者在运行期创建接口的代理实例。在Sun刚推出动态代理时,还很难想象它有多大的实际用途,现在动态代理是实现AOP的绝好底层技术。
JDK的动态代理主要涉及java.lang.reflect包中的两个类:Proxy和InvocationHandler。其中InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一起。而Proxy为InvocationHandler实现类动态创建一个复合某一接口的代理的实例。
JDK动态代理其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类完成对目标对象的代理。这点也是与CGLIB代理最大不同之处,CGLIB代理是针对类生成代理。
JDK动态代理的使用
要想模拟JDK动态代理的实现,首先要明白它的内在机理,知道它对外开放的接口方法。借用上篇文章中记录JDK动态代理时的简单示例,仅包括两个类:TimeHandler类和Test类,来回顾下JDK动态代理的使用。
package com.jdkproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* JDK动态代理步骤:
* 1创建一个实现InvocationHandler的类,必须实现invoke方法
* 2.创建被代理的类和接口
* 3.调用Proxy的静态方法,创建一个代理类
* 4.通过代理调用方法.
*
*/
public class TimeHandler implements InvocationHandler {
private Object object;
public TimeHandler(Object object) {
super();
//代理对象
this.object = object;
}
/**
* proxy: 代理对象
* method: 被代理对象的方法
* args:方法的参数
* return: 调用方法的返回值
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long startTime = System.currentTimeMillis();
System.out.println("汽车开始行驶");
method.invoke(object);
long endTime = System.currentTimeMillis();
System.out.println("汽车行驶结束,行驶时间为:"+(endTime-startTime)+" ms");
return null;
}
}
package com.jdkproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import com.proxy.Car;
import com.proxy.Moveable;
public class Test {
public static void main(String[]args){
Car car = new Car();
InvocationHandler h = new TimeHandler(car);
Class<?> cls = car.getClass();
/**
* loader:类加载器
* interfaces:实现的接口
* h InvocationHandler
*/
Moveable m = (Moveable) Proxy.newProxyInstance(
cls.getClassLoader(), cls.getInterfaces(), h);
m.move();
}
}
运行结果:
JDK动态代理实现思路
如以上Test类中,通过Proxy的newProxyInstance()方法动态产生一个代理。模拟JDK动态代理实现流程,同样要自定义一个Proxy类并在类中实现产生动态代理的方法,这也是实现JDK动态代理的关键点和主要功能。
动态代理实现步骤如下
- 声明一段源码(动态产生代理)
- 编译源码(JDK Compiler API),产生代理类
- 将新产生的代理类load到内存当中,产生一个新的对象即代理对象
- 在newProxyInstance方法中返回这个代理对象
声明一段源码(动态产生代理)
将源码定义为字符串,Proxy类中代码如下:
package com.myJDKproxy;
public class Proxy {
public static Object newProxyInstance(){
String rt = "\r\t";
String str =
"package com.myJDKproxy;" + rt +
"public class $Proxy0 implements Moveable{"+ rt +
"private Moveable m;"+ rt +
" public $Proxy0(Moveable m) {"+ rt +
" super();"+ rt +
" this.m = m;"+ rt +
" }"+ rt +
" @Override"+ rt +
" public void move() {"+ rt +
" long startTime = System.currentTimeMillis();"+ rt +
" System.out.println(\"汽车开始行驶\");"+ rt +
" m.move();"