首页 > 代码库 > JDK动态代理

JDK动态代理

    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的动态代理是针对接口的代理,即增强目标类必须是实现了某一个或多个接口的类,其被增强的方法也必须是接口中的方法,之所以称之为动态代理是因为对实例的代理发生在运行期,另外代理还可以发生在编译期和装载期(需要特殊的编译器和装载器)。


本文出自 “埃文” 博客,请务必保留此出处http://wenshengzhu.blog.51cto.com/5151285/1599445

JDK动态代理