JDK 1.3以后,java提供了动态代理的技术,允许开发者在运行初期创建接口的代理实例。所谓代理即对某一实例的增强,对象在实例化的时候得到增强,增强过的实例即为代理实例,代理实例往往在运行的时候被动态增强。
JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。其中InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,并通过反射机制调用目标类代码,动态地将横切逻辑和业务逻辑编织在一起。
而Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。下面通过一组实例演示如何使用JDK的动态代理。
FormService.java
public interface FormService {
/**
* 模拟论坛话题被删除
* @param topicId
*/
public void removeTopic(int topicId);
/**
* 模拟论坛被删除
* @param forumId
*/
public void removeForum(int forumId);
}
FormServiceImpl.java
public class FormServiceImpl implements FormService {
@Override
public void removeTopic(int topicId) {
System.out.println("模拟删除Topic记录:" + topicId);
try {
Thread.sleep(20);
} catch (InterruptedException e) {
throw new RuntimeException();
}
}
@Override
public void removeForum(int forumId) {
System.out.println("模拟删除Topic记录:" + forumId);
try {
Thread.sleep(40);
} catch (InterruptedException e) {
throw new RuntimeException();
}
}
}
PerformanceHandler.java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class PerformanceHandler implements InvocationHandler {
private Object target;
public PerformanceHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] params)
throws Throwable {
String methodName = target.getClass().getName() + "." + method.getName();
System.out.println("对" + methodName + "方法进行性能检测。");
long start = System.currentTimeMillis();
Object obj = method.invoke(target, params);
long end = System.currentTimeMillis();
System.out.println(methodName +"方法用时:" + (end - start) + "毫秒。");
return obj;
}
}
测试类TestForProxy.java
import java.lang.reflect.Proxy;
public class TestForProxy {
public static void main(String[] args) {
FormService forumService = new FormServiceImpl();
PerformanceHandler handler = new PerformanceHandler(forumService);
FormService proxy = (FormService) Proxy.newProxyInstance(
forumService.getClass().getClassLoader(),
forumService.getClass().getInterfaces(),handler);
proxy.removeForum(10);
proxy.removeTopic(1012);
}
}
程序运行运行结果:
对org.proxy.jdkproxy.FormServiceImpl.removeForum方法进行性能检测。
模拟删除Topic记录:10
org.proxy.jdkproxy.FormServiceImpl.removeForum方法用时:40毫秒。
对org.proxy.jdkproxy.FormServiceImpl.removeTopic方法进行性能检测。
模拟删除Topic记录:1012
org.proxy.jdkproxy.FormServiceImpl.removeTopic方法用时:20毫秒。
在以上代码中,我们实现了InvocationHandler接口,该接口定义了一个invoke(Object proxy,Method method,Object[] params)的方法,proxy是最终生成的代理实例,一般不会用到;method是被代理目标实例的某个具体方法,通过他可以发起目标实例方法的反射调用;params是通过被代理实例某一具体方法的入参,在方法反射时使用它。
注意:JDK的动态代理是针对接口的代理,即增强目标类必须是实现了某一个或多个接口的类,其被增强的方法也必须是接口中的方法,之所以称之为动态代理是因为对实例的代理发生在运行期,另外代理还可以发生在编译期和装载期(需要特殊的编译器和装载器)。
转载于:https://blog.51cto.com/wenshengzhu/1599445