为其他对象提供一种代理以控制对这个对象的访问
举个例子
金鹏驾校开张了。正常报名的话,我们都要去驾校排队报名。瑞哥觉得有人不想排队,就想出来了一个生财的道道。瑞哥要给鹏哥做代理。报名直接找瑞哥就行了。但是瑞哥觉得收钱爽,退钱不爽。所以就只做报名收钱这个,如果觉得报名后悔的话,还得找鹏哥要钱。说白了就是:为其他对象提供一种代理以控制对这个对象的访问。可以去掉或增加额外的功能。
代理的种类
1. 远程代理
为不同地理的对象提供局域网代表对象
2. 虚拟代理
根据需要将资源消耗比较大的对象进行延迟,真正需要的时候在进行创建
3. 智能代理
两种实现方式:静态代理,动态代理
4. 保护代理
可以简单理解为控制对一个对象的访问权限
智能引用代理
静态代理
代理和被代理对象在代理之前是确定的,他们都实现了相同的接口或者继承了相同的抽象类。

public class ProxyDemo {
public static void main(String args[]){
RealSubject subject = new RealSubject();
Proxy p = new Proxy(subject);
p.request(); }
}
interface Subject{
void request();
}
class RealSubject implements Subject{
public void request(){
System.out.println("request");
}
}
class Proxy implements Subject{
private Subject subject;
public Proxy(Subject subject){
this.subject = subject;
}
public void request(){
System.out.println("PreProcess");
subject.request();
System.out.println("PostProcess");
}
}
动态代理
代理类是在运行时生成的。也就是说 Java 编译完之后并没有实际的 class 文件,而是在运行时动态生成的类字节码,并加载到JVM中。
public class DynamicProxyDemo01 {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();//1.创建委托对象
ProxyHandler handler = new ProxyHandler(realSubject);//2.创建调用处理器对象
Subject proxySubject = (Subject)Proxy.newProxyInstance(RealSubject.class.getClassLoader(),
RealSubject.class.getInterfaces(), handler);//3.动态生成代理对象
proxySubject.request();//4.通过代理对象调用方法
}
}
/**
* 接口
*/
interface Subject{
void request();
}
/**
* 委托类
*/
class RealSubject implements Subject{
public void request(){
System.out.println("====RealSubject Request====");
}
}
/**
* 代理类的调用处理器
*/
class ProxyHandler implements InvocationHandler{
private Subject subject;
public ProxyHandler(Subject subject){
this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("====before====");//定义预处理的工作,当然你也可以根据 method 的不同进行不同的预处理工作
Object result = method.invoke(subject, args);
System.out.println("====after====");
return result;
}
}
static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler handler)
{
//1. 根据类加载器和接口创建代理类
Class clazz = Proxy.getProxyClass(loader, interfaces);
//2. 获得代理类的带参数的构造函数
Constructor constructor = clazz.getConstructor(new Class[] { InvocationHandler.class });
//3. 创建代理对象,并制定调用处理器实例为参数传入
Interface Proxy = (Interface)constructor.newInstance(new Object[] {handler});
}
这个函数是在代理对象调用任何一个方法时都会调用的,方法不同会导致第二个参数method不同,第一个参数是代理对象(表示哪个代理对象调用了method方法),第二个参数是 Method 对象(表示哪个方法被调用了),第三个参数是指定调用方法的参数。
动态生成的代理类具有几个特点:
- 继承 Proxy 类,并实现了在Proxy.newProxyInstance()中提供的接口数组。
- public final。
- 命名方式为 $ProxyN,其中N会慢慢增加,一开始是 $Proxy1,接下来是$Proxy2...
- 有一个参数为 InvocationHandler 的构造函数。这个从 Proxy.newProxyInstance() 函数内部的clazz.getConstructor(new Class[] { InvocationHandler.class }) 可以看出。
Java 实现动态代理的缺点:因为 Java 的单继承特性(每个代理类都继承了 Proxy 类),只能针对接口创建代理类,不能针对类创建代理类。
不难发现,代理类的实现是有很多共性的(重复代码),动态代理的好处在于避免了这些重复代码,只需要关注操作。
Java 动态代理的内部实现
现在我们就会有一个问题: Java 是怎么保证代理对象调用的任何方法都会调用 InvocationHandler 的 invoke() 方法的?
这就涉及到动态代理的内部实现。假设有一个接口 Subject,且里面有 int request(int i) 方法,则生成的代理类大致如下:
public final class $Proxy1 extends Proxy implements Subject{
private InvocationHandler h;
private $Proxy1(){}
public $Proxy1(InvocationHandler h){
this.h = h;
}
public int request(int i){
Method method = Subject.class.getMethod("request", new Class[]{int.class}); //创建method对象
return (Integer)h.invoke(this, method, new Object[]{new Integer(i)}); //调用了invoke方法
}
}
通过上面的方法就成功调用了 invoke() 方法。