定义:
Provide a surrogate or placeholder for another object to control access to it.
为其他对象提供一种代理以控制对这个对象的访问。
定义说的简明扼要,代理模式就是提供了另一种访问对象的方式。
代理有四大类:
1.远程代理(Remote Proxy): 控制对远程对象(不同地址空间)的访问,它负责将请求及其参数进行编码,并向不同地址空间中的对象发送已经编码的请求。
2.虚拟代理(Virtual Proxy): 根据需要创建开销很大的对象,它可以缓存实体的附加信息,以便延迟对它的访问,例如在网站加载一个很大图片时,不能马上完成,可以用虚拟代理缓存图片的大小信息,然后生成一张临时图片代替原始图片。
3.保护代理(Protection Proxy): 按权限控制对象的访问,它负责检查调用者是否具有实现一个请求所必须的访问权限。
4.智能代理(Smart Reference): 取代了简单的指针,它在访问对象时执行一些附加操作: 记录对象的引用次数;当第一次引用一个持久化对象时,将它装入内存;在访问一个实际对象前,检查是否已经锁定了它,以确保其它对象不能改变它。
代理模式有两种:
1.静态代理: 在编译时就已经实现,编译完成后代理类是一个实际的class文件。
2.动态代理: 在运行时动态生成的,即编译完成后没有实际的class文件,而是在运行时动态生成类字节码,并加载到JVM中。
UML图
下面我们通过代码【RUNOOB的例子】来看一下静态代理
1.创建接口
public interface Image {
void display();
}
2.创建实现类,即被代理的对象
public class RealImage implements Image {
private String fileName;
public RealImage(String fileName){
this.fileName = fileName;
}
@Override
public void display() {
System.out.println("This is" + fileName);
}
}
3.创建代理类
public class ProxyImage implements Image{
private RealImage realImage;
private String fileName;
//构造代理对象时传入目标对象
public ProxyImage(String fileName,RealImage realImage){
this.fileName = fileName;
this.realImage = realImage;
}
@Override
public void display() {
realImage.display();
}
}
4.测试,使用代理获取对象
public class ProxyPatternDemo {
public static void main(String[] args) {
RealImage realImage = new RealImage();
//创建代理对象
Image image = new ProxyImage("01.jpg",realImage);
image.display();
}
}
通过代码可以看出,静态代理的缺点暴露了出来:由于代理只能为一个类服务,如果需要代理的类很多,那么就需要编写大量的代理类,比较繁琐。
动态代理
使用JDK动态代理的三大步骤:
- 通过实现InvocationHandler接口来自定义自己的InvocationHandler
- 通过Proxy.newProxyInstance( )方法创建动态代理对象
- 通过代理对象调用目标方法
public interface IHello {
void sayHello();
}
public class HelloImpl implements IHello {
@Override
public void sayHello() {
System.out.println("Hello world!");
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
/** 目标对象(被代理对象) */
private IHello target;
public MyInvocationHandler(IHello target){
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("------插入前置通知代码-------------");
// 执行相应的目标方法
Object rs = method.invoke(target,args);
System.out.println("------插入后置处理代码-------------");
return rs;
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class MyProxyTest {
public static void main(String[] args) throws Exception {
IHello iHello = (IHello) Proxy.newProxyInstance(IHello.class.getClassLoader(), // 加载接口的类加载器
new Class[]{IHello.class}, // 一组接口
new MyInvocationHandler(new HelloImpl())); // 自定义的InvocationHandler
iHello.sayHello();
}
}
动态代理深入:
TODO 待补充… …
静态代理和动态代理的区别:
JDK静态代理是通过直接编码创建的,而JDK动态代理是利用反射机制在运行时创建代理类的。
总结
1.优点:
1、职责清晰。 2、高扩展性。 3、智能化。
2.缺点:
1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。