1、书中的定义
书里的定义:利用代理可以在运行时创建实现了一组给定接口的新类。只有在编译时期无法确定需要实现哪个接口时才有必要使用代理。
- 本书给的例子是:想构造一个类的对象,这个类实现了一些接口,但是编译的时候你不知道这些接口到底是什么。代理类可以在运行时创建全新的类,代理类能实现指定接口。
这个定义感觉比较难以理解。但是先看下代理要实现需要的几个要素。
构造一个代理对象需要三个参数:
- 类加载器
- 一个Class对象数组,每个元素对应需要实现的各个接口
- 一个调用处理器,这个调用处理器是实现了InvocationHandler接口的类的对象,只有一个方法Object invoke(Object proxy, Method method Object[] args) 无论何时调用代理对象的方法,调用处理器的invoke方法都会被调用,并向其传递Method对象和原调用参数。
2、其他博客以及实例
看了下其他博客,大家大多给出的代理的用处是 代理的意义在于生成代理对象,在服务提供方和使用方之间充当一个媒介,控制真实对象的访问。
就是构造了这个代理对象后,你调用方法就会经过这个代理对象,这个代理对象就可以展开一些其他操作。
https://www.cnblogs.com/xdp-gacl/p/3971367.html
https://blog.csdn.net/weixin_43320847/article/details/82938754
结合上面两篇博客和书中的例子看,这是书中的例子
2.1 书中的例子
- 调用处理器就是 TraceHandler 它代理的就是
private Object target
- 构造代理对象的时候提供了三个参数
Object proxy = Proxy.newProxyInstance(null, new Class[] { Comparable.class } , handler);
- 代理的对象实现了Compare接口
- 在这个例子中
Arrays.binarySearch(elements, key)
会调用compareTo方法,但是elements存的是proxy对象,代理value这个对象,compareTo会经过handler 调用,调用的时候就会经过TraceHandler 里面invoke的一堆print,最后就会输出500.compareTo(x)这样的内容。如果elements里就存的value,那就什么都不会打印。
import java.lang.reflect.*;
import java.util.*;
/**
* This program demonstrates the use of proxies.
* @version 1.00 2000-04-13
* @author Cay Horstmann
*/
public class ProxyTest
{
public static void main(String[] args)
{
Object[] elements = new Object[1000];
// fill elements with proxies for the integers 1 ... 1000
for (int i = 0; i < elements.length; i++)
{
Integer value = i + 1;
InvocationHandler handler = new TraceHandler(value);
Object proxy = Proxy.newProxyInstance(null, new Class[] { Comparable.class } , handler);
elements[i] = proxy;
}
// construct a random integer
Integer key = new Random().nextInt(elements.length) + 1;
// search for the key
int result = Arrays.binarySearch(elements, key);
// print match if found
if (result >= 0) System.out.println(elements[result]);
}
}
/**
* An invocation handler that prints out the method name and parameters, then
* invokes the original method
*/
class TraceHandler implements InvocationHandler
{
private Object target;
/**
* Constructs a TraceHandler
* @param t the implicit parameter of the method call
*/
public TraceHandler(Object t)
{
target = t;
}
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable
{
// print implicit argument
System.out.print(target);
// print method name
System.out.print("." + m.getName() + "(");
// print explicit arguments
if (args != null)
{
for (int i = 0; i < args.length; i++)
{
System.out.print(args[i]);
if (i < args.length - 1) System.out.print(", ");
}
}
System.out.println(")");
// invoke actual method
return m.invoke(target, args);
}
}
2.2 shop例子
https://blog.csdn.net/weixin_43320847/article/details/82938754
- 代理的对象是
Shoping client
它实现的是Shopinng接口 - 构造代理对象
Shopping shop = (Shopping) Proxy.newProxyInstance(Shopping.class.getClassLoader(), new Class[]{Shopping.class}, dyProxy);
- 调用处理器 DynamicProxy
- 最后
shop.buy()
就不只是打印一句话,而是经过处理器,前后多打印一句话
interface Shopping {
void buy();
}
// 例子中被代理的
class Client implements Shopping {
public void buy() {
System.out.println("我想买这件商品");
}
}
// 调用处理器
public class DynamicProxy implements InvocationHandler {
private Object target = null;
DynamicProxy(Object target) {
this.target = target;
}
/**
* 代理方法逻辑
*
* @param proxy 代理对象
* @param method 调度方法
* @param args 调度方法参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理前");
method.invoke(target, args);
System.out.println("代理后");
return null;
}
}
public class DyProxyTest {
public static void main(String[] args) {
Shopping client = new Client();
// 调用处理器
DynamicProxy dyProxy = new DynamicProxy(client);
// 构造代理对象
Shopping shop = (Shopping) Proxy.newProxyInstance(Shopping.class.getClassLoader(), new Class[]{Shopping.class}, dyProxy);
shop.buy();
}
}
// 结果:
// 代理前
// 我想买这件商品
// 代理后
2.3 ldh例子
- 代理的对象是
private Person ldh = new LiuDeHua();
,实现的接口是Person - 调用
p.sing("冰雨")
的时候,就经过了handler,输出了额外的一些内容