什么是代理模式
代理模式是为另一个对象提供一个替身或占位符以控制对这个对象的访问。
- 关键词:提供替身或占位符
- 目的:控制对目标对象的访问
类图
- Subject: 定义RealSubject的行为,同时Proxy为了保持和RealSubject行为一致,也要实现该接口。
- RealSubject:被代理对象,即最终真正要执行的对象。
- Proxy: 持有Subjcet的引用,并负责创建RealSubject对象。
代理Proxy持有Subject接口的引用,并负责创建真正的RealSubject对象,调用方想和RealSubject交互都要经过Proxy,这样就做了一次隔离,使得RealSubject被保护起来。举个例子,就想一个企业想邀请某个明星去参加活动,企业并不能直接联系明星,而是通过明星的经纪人间接地同明星联系,其中经纪人的角色就相当于一个代理。代理模式分为静态代理和动态代理,下面分别来看下:
静态代理
//定义被代理对象接口
public interface ISSubject {
void say();
}
//被代理对象
public class RealSSubject implements ISSubject {
@Override
public void say() {
System.out.println("我是静态代理对象!");
}
}
//静态代理类
public class StaticProxy implements ISSubject {
ISSubject realSubject;
public StaticProxy(ISSubject realSubject) {
this.realSubject = realSubject;
}
@Override
public void say() {
realSubject.say();
}
}
代用静态代理类:
//静态代理
StaticProxy staticProxy=new StaticProxy(new RealSSubject());
staticProxy.say();
执行结果:
我是静态对象!
静态代理类只有被代理类接口的引用,并创建了被代理类,所以可以控制对被代理类的访问。但是静态代理有个缺点,当我们的被代理类很多时,需要的静态代理类会很多。如何统一代理功能呢,接着来看动态代理:
动态代理
public interface ISubject {
void say();
}
public class RealSubject implements ISubject {
@Override
public void say() {
System.out.println("我是动态代理对象!");
}
}
//InvocationHandler是代理类的辅助类
public class DynamicHandler implements InvocationHandler {
private ISubject target;
public DynamicHandler(ISubject target) {
this.target = target;
}
public Object bind() {
//通过反射得到代理类
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] objects) throws Throwable {
//调用被代理类对应的方法
return method.invoke(target, objects);
}
}
调用动态代理:
//动态代理
DynamicHandler handler = new DynamicHandler(new RealSubject());
ISubject subject = (ISubject) handler.bind();
subject.say();
执行结果:
我是动态代理对象!
动态代理,顾名思义,并不是在编译阶段就生成的代理类,而是在运行时动态生成的。动态代理主要是通过Proxy类、InvocationHandler类实现的,首先通过Proxy.newProxyInstance(ClassLoader var0, Class<?>[] var1, InvocationHandler var2)
得到代理实例,我们看到生成代理对象实例时还传入了一个InvocationHandler(我们手动实现的InvocationHandler子类),在代理对象内部每个方法都会调用InvocationHandler的invoke方法,而在我们手动实现的invoke方法中,又会调用目标类的方法,从而实现了动态代理。所以,InvocationHandler其实是代理类的一个辅助类,是代理对象和被代理对象之间的桥梁。
动态代理相比于静态代理,代码量比较固定,不会因为被代理类变多而变多。因为动态代理不需要提前实例化,所以更加灵活。除了控制目标对象,还可以在执行目标对象方法(调用invoke方法时)的前后添加额外的逻辑,比如在方法前后进行埋点。
装饰者模式 VS 代理模式
装饰者模式和代理模式有一定的相似度,但他们的职责是完全不相同的。装饰者模式是为了给目标对象添加行为,而代理模式是为了控制对目标对象的访问。
参考
【1】动态代理与静态代理区别