Java 代理之动态代理

通过使用代理可以隐藏委托类的实现,并且实现客户与委托类之间的解耦,在不修改委托类的前提下为客户做一些额外处理

类型

  1. 静态代理 - Java 代理之静态代理
    • 虽然具备代理的两个优点
    • 但局限在于运行前必须编写好代理类
  2. 动态代理
    • 代理类在程序运行时才被创建
    • 其优势在于可以对多个代理类进行统一处理,而不用修改每个代理类的实现

定义 InvocationHandler 接口,充当调用处理器

  1. java.lang.reflect.InvocationHandler 是 Java 自带的调用处理器
  2. 为处于代理类和委托类之间的中间类提供实现接口
  3. 代理类作为参数 proxy 传入
  4. 参数 method 标识具体调用代理类的哪个方法
  5. 参数 args 是这个代理类方法的参数
1
2
3
public interface InvocationHandler {
	Object invoke(Object proxy, Method method, Object[] args);
}

定义委托类,使用动态代理,委托类必须实现某个接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Sell {
	void sell();

	void ad();
}

public class Vendor implements Sell {
	public void sell() {
		System.out.println("In sell method");
	}

	public void ad() {
		System.out.println("In ad method");
	}
}

定义中介类,其必须实现 InvocationHandler 接口

  1. 该类持有一个委托类的引用
  2. 中介类和委托类构成静态代理,中介类充当代理类,委托类依旧是委托类
  3. 中介类和代理类构成静态代理,中介类充当委托类,代理类依旧是代理类
  4. 所以实际上动态代理是由两组静态代理组成
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class DynamicProxy implements InvocationHandler {
	private Object object;

	public DynamicProxy(Object object) {
		this.object = object;
	}

	public void invoke(Object proxy, Mehtod method, Object[] args) {
		System.out.println("-- before --");
		Object result = method.invoke(object, args);
		System.out.println("-- after --");

		return result;
	}
}

动态生成代理类

  1. 通过调用 Proxy.newProxyInstance() 获取代理类实例,其实现指定接口并将方法滴啊用分发到指定的调用处理器
  2. 该方法的声明 public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
  3. 参数 loader 是定义了代理类的 ClassLoader
  4. 参数 interfaces 是代理类实现的接口列表
  5. 参数 h 是调动处理器
1
2
3
4
5
6
7
8
9
10
public class MainTest {
	public static void main(String[] args) {
		DynamicProxy dynamicProxy = new DynamicProxy(new Vendor());

		Sell sell = (Sell) Proxy.newProxyInstance(Sell.class.getClassLoader(), new Class[]{Sell.class}, dynamicProxy);

		sell.sell();
		sell.ad();
	}
}