JDK动态代理实现

代理模式是设计模式中比较重要也比较常用的模式,静态代理靠我们手工完成代理类,这是一项比较耗时和费力的工作,一旦被代理接口发生改变需要修改的地方也比较多。但是动态代理就不会产生这样的后遗症。java动态代理的出现,只要简单地指定一组接口及委托类对象,便能动态地获得代理类。

我们来看一下相关的类和接口:

1.java.lang.reflect.Proxy:这是 Java 动态代理机制的主类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。

// 方法 1: 该方法用于获取指定代理对象所关联的调用处理器

static InvocationHandler getInvocationHandler(Object proxy) 

// 方法 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象

static Class getProxyClass(ClassLoader loader, Class[] interfaces) 

// 方法 3:该方法用于判断指定类对象是否是一个动态代理类

static boolean isProxyClass(Class cl) 

// 方法 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例

static Object newProxyInstance(ClassLoader loader, Class[] interfaces,     InvocationHandler h)

2.java.lang.reflect.InvocationHandler:这是调用处理器接口,它自定义了一个 invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。

该方法负责集中处理动态代理类上的所有方法调用。第一个参数既是代理类实例, 第二个参数是被调用的方法对象

// 第三个方法是调用参数。调用处理器根据这三个参数进行预处理或分派到委托类实 例上发射执行

Object invoke(Object proxy, Method method, Object[] args)

3.java.lang.ClassLoader:这是类装载器类,负责将类的字节码装载到 Java 虚拟机(JVM)中并为其定义类对象,然后该类才能被使用。Proxy 静态方法生成动态代理类同样需要通过类装载器来进行装载才能使用,它与普通类的唯一区别就是其字节码是由 JVM 在运行时动态生成的而非预存在于任何一个 .class 文件中。

java动态代理的实现步骤:

1 通过实现 InvocationHandler 接口创建自己的调用处理器;

2 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;

3 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;

4 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。


做一个小实验:
package reflectionanddynamicprosy;

/**
 * 接口类
 * 
 * @author Administrator
 *
 */
public interface DaoClass {
	public int getAutheration();

	public void setAutheration(int autheration);

	public int getId();

	public void save();

	public void delete();
}

package reflectionanddynamicprosy;

import java.util.Random;
/**
 * 被代理对象
 * 实现了DaoClass接口
 * 
 * @author Administrator
 *
 */
public class DaoClassImpl implements DaoClass {
	private int autheration;
	
	public DaoClassImpl(int a) {
		this.autheration = a;
	}
	
	@Override
	public void delete() {
		System.out.println("删除");
	}

	@Override
	public int getId() {
		Random r = new Random(47);
		int num = r.nextInt(20);
		return num;
	}

	@Override
	public void save() {
		System.out.println("保存");
	}

	public int getAutheration() {
		return autheration;
	}

	public void setAutheration(int autheration) {
		this.autheration = autheration;
	}

}

package reflectionanddynamicprosy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * 实现 InvocationHandler 接口创建自己的调用处理器
 * 
 * @author Administrator
 *
 */
public class DaoClassProxy implements InvocationHandler {
	private Object targetObj;

	public DaoClassProxy(DaoClass dc) {
		this.targetObj = dc;
	}

	//生成代理类
	public Object createProxyInstance() {
		// 为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类
		// 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入
		return Proxy.newProxyInstance(this.targetObj.getClass()
				.getClassLoader(), this.targetObj.getClass().getInterfaces(),
				this);
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		DaoClassImpl dcl = (DaoClassImpl) this.targetObj;
		if (dcl.getAutheration() < 0) {
			throw new Exception("权限太低");
		} else if (dcl.getAutheration() > 5) {
			throw new Exception("权限为定置");
		} else
			return method.invoke(dcl, args);
	}

}

package reflectionanddynamicprosy;

public class TestProxy {
	public static void main(String[] args) {
		DaoClassProxy proxy = new DaoClassProxy(new DaoClassImpl(10));
		DaoClass dcl = (DaoClass) proxy.createProxyInstance();
		dcl.save();
		dcl.delete();
	}
}
测试结果:Exception in thread "main" java.lang.reflect.UndeclaredThrowableException
	at $Proxy0.save(Unknown Source)
	at reflectionanddynamicprosy.TestProxy.main(TestProxy.java:7)
Caused by: java.lang.Exception: 权限为定置
	at reflectionanddynamicprosy.DaoClassProxy.invoke(DaoClassProxy.java:35)
	... 2 more
我们在测试结果中看到了$Proxy0.save()这样的信息,$Proxy0这就是jdk动态生成的DaoClassImpl类。当然如果我们设置了正确的权限就会打印:保存和删除信息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值