代理模式
代理模式
1.定义
- 代理模式,为其他对象提供一种代理以控制对这个对象的访问。
- 代理对象在客户端和目标对象之间起到中介作用。属于结构型设计模式。
package cn.sun.code.seven;
/**
* Subject类,定义了RealSubject和Proxy的公共接口,这样就在任何使用RealSubject的地方都可以
* 使用Proxy
*/
interface Subject {
void request();
}
/**
* RealSubject类,定义Proxy所代表的真实实体
*/
class RealSubject implements Subject {
@Override
public void request() {
System.out.println("真实的请求");
}
}
/**
* Proxy类,保存一个引用使得代理可以访问实体,并提供一个与Subject的接口相同的接口
* 这样代理就可以用来代替实体
*/
public class Proxy implements Subject {
private RealSubject realSubject;
@Override
public void request() {
// 可以在这里给被代理对象定制一些特性
if (realSubject == null) {
realSubject = new RealSubject();
}
System.out.println("对委托类开始增强");
realSubject.request();
System.out.println("对委托类增强结束");
}
}
/**
* 客户端代码
*/
class Client {
public static void main(String[] args) {
Proxy proxy = new Proxy();
proxy.request();
}
}
2.为什么使用代理模式
- 代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。
3.静态代理
-
静态代理在使用时,需要定义接口或者父类,被代理对象与与代理对象一起实现相同的接口或者是继承相同父类。
- 定义中的示例即为标准静态代理方式。
- 关键,在编译期确定代理对象,在程序运行前代理类的.class文件就已经存在。
-
静态代理的缺陷:
- 每个代理类都必须实现一遍委托类(realSubject)的接口,如果接口增加方法,则代理类也必须跟着修改。增加了代码维护的复杂度。
4.动态代理
- 动态代理是根据代理的对象,动态创建代理类。
- 动态代理是通过反射实现的,可以借助Java自带的
java.lang.reflect.Proxy
实现- 编写一个委托类的接口,即静态代理中的Subject接口
- 实现一个委托类,即静态代理中的RealSubject类
- 创建一个动态代理类,实现
InvocationHandler
接口,并重写该invoke()
方法 - 在客户端中,生成动态代理对象
package cn.sun.code.seven;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 动态代理类
*/
public class DynamicProxy implements InvocationHandler {
private Object object;
public DynamicProxy(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("对委托类开始增强");
Object invoke = method.invoke(object, args);
System.out.println("对委托类增强结束");
return invoke;
}
}
/**
* 客户端对象
*/
class Client2 {
public static void main(String[] args) {
Subject realSubject = new RealSubject();
DynamicProxy proxy = new DynamicProxy(realSubject);
ClassLoader classLoader = realSubject.getClass().getClassLoader();
Subject subject = (Subject) Proxy.newProxyInstance(classLoader, new Class[]{Subject.class}, proxy);
subject.request();
}
}
-
InvocationHandler
接口说明/** * {@code InvocationHandler} is the interface implemented by * the <i>invocation handler</i> of a proxy instance. * * <p>Each proxy instance has an associated invocation handler. * When a method is invoked on a proxy instance, the method * invocation is encoded and dispatched to the {@code invoke} * method of its invocation handler. * */
-
每一个动态代理类都必须要实现
InvocationHandler
这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler
这个接口的 invoke 方法来进行调用。 -
invoke()
方法-
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; // proxy:指我们所代理的那个真实对象 // method:指我们所要调用真实对象的某个方法的method对象 // args:指调用真实方法某个对象时所接受的参数
-
-
-
Proxy类说明
-
Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.
-
Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了许多静态方法,但是我们用的最多的就是
newProxyInstance()
这个方法:-
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
- loader:一个ClassLoader对象,定义由哪个ClassLoader对象来对生成的代理对象进行加载
- interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口,这样生成的代理类就能调用这组接口中的方法了
- h:一个InvocationHandler对象,表示的是当这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
-
-