一、动态代理的步骤
1、先编写公共接口和实现此接口的目标类(被代理类)。
2、编写实现了InvocationHandler接口的类,在这个类中一般会有接口对象,和一个invoke方法,在invoke中通过接口调用目标类的方法,同时添加自己的方法。
3、通过newProxyInstance静态方法创建代理类。
// 编写公共接口
package service;
/**
* 在静态代理中,代理类和目标类都必须实现相同的接口,因为对于客户端来说,
* 使用代理类就像使用目标类一样,所以二者必须实现相同的接口,具有相同的特性。
*/
public interface OrderService {
/**
* 生成订单
*/
void generate();
/**
* 修改订单
*/
void modify();
/**
* 查看订单
*/
void detail();
}
// 编写实现类(目标类,被代理类)
package service;
public class OrderServiceImpl implements OrderService{
public void generate() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("订单已经生成");
}
@Override
public void modify() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("订单已经修改");
}
@Override
public void detail() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("订单信息如下");
}
}
// 编写调用处理器,在这里面通过属性调用方法
package service;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class TimeInvocationHandler implements InvocationHandler {
// 目标对象
OrderService orderService;
public TimeInvocationHandler(OrderService orderService) {
this.orderService = orderService;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Long begin = System.currentTimeMillis();
// 通过属性调用方法,完成了目标类中的目标方法,其他的都是增强功能
Object invoke = method.invoke(orderService, args);
long end = System.currentTimeMillis();
System.out.println("耗时"+(end-begin)+"毫秒");
return null;
}
}
// 测试程序
package client;
import service.OrderService;
import service.OrderServiceImpl;
import service.TimeInvocationHandler;
import java.lang.reflect.Proxy;
public class test {
public static void main(String[] args) {
// 创建目标对象
OrderService orderService = new OrderServiceImpl();
// 创建代理对象
OrderService proxyInstance = (OrderService) Proxy.newProxyInstance(orderService.getClass().getClassLoader(),
orderService.getClass().getInterfaces(),
new TimeInvocationHandler(orderService));
// 调用方法
proxyInstance.generate();
// proxyInstance.modify();
// proxyInstance.detail();
}
}
二、动态代理源码的简单理解
在借鉴了其他博主的介绍下,只介绍最简单的逻辑理解,即代码 Proxy.newProxyInstance(...)的逻辑。
简单说就是在底层生成了class文件,我们要获取此calss文件(class对象),然后通过反射得到参数为“调用处理器对象”构造方法,最后通过构造方法实例化对象。
底层生成的class文件所对象的类,实现了公共接口并且继承了Proxy。实现是基于代理类必须和被代理类实现同一个接口。继承则是在于调用此对象时,可以调用父类Proxy中的invoke方法。这样只要将相应方法和参数传给父类Proxy的invoke方法就行。
参考:
这些只是我为了好理解,简单地说法,具体内部实现可参考一下两篇文章