设计模式之代理模式
定义
为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
特点:
- 真实对象职责清晰
- 客户端直接调用代理端,保护真实对象
UML结构图

- Subject:抽象角色,定义操作
- Proxy:代理对象,持有真实对象;客户端直接操作对象
- RealSubject:真实对象,只关心自己实现的内容
分类
静态代理
- 服务类
/**
* 需要代理的方法
*/
public interface Subject {
void execute();
}
- 实际对象
/**
* 实际的对象
*/
public class RealSubject implements Subject {
@Override
public void execute() {
System.out.println("RealSubject execute");
}
}
- 代理类
public class Proxy implements Subject {
private Subject subject;
public Proxy(Subject subject) {
this.subject = subject;
}
@Override
public void execute() {
System.out.println("Proxy execute");
if (subject != null) {
subject.execute();
}
}
}
小结:
- 每个服务都必须创建一个代理对象。
动态代理
- 服务类
/**
* 需要代理的方法
*/
public interface Subject {
void execute();
}
- Handler-用于生成代理对象
/**
* InvocationHandler 生成代理对象
*/
public class DynamicProxyHandler implements InvocationHandler {
private Subject subject;
public DynamicProxyHandler(Subject subject) {
this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("DynamicProxyHandler invoke");
return method.invoke(subject, args);
}
}
小结:
依赖于接口
注意 Proxy.newProxyInstance()方法接受三个参数:
- ClassLoader loader:指定当前目标对象使用的类加载器,获取加载器的方法是固定的
- Class<?>[] interfaces:指定目标对象实现的接口的类型,使用泛型方式确认类型
- InvocationHandler:指定动态处理器,执行目标对象的方法时,会触发事件处理器的方法
Cglib代理
注意:使用前需提前导入ASM和Cglib的jar包。
CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。但因为采用的是继承,所以不能对final修饰的类进行代理。
脱离了接口以及代理类。
- 真实对象
/**
* 真实对象
*/
public class SubjectCglib {
public void execute() {
System.out.println("Subject execute");
}
}
- Cglib拦截器
/**
* Cglib 方法拦截器
*/
public class CglibInterceptor implements MethodInterceptor {
public <T> T createProxy(Class<T> targetClass) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetClass);
enhancer.setCallback(this);
return (T) enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("CglibInterceptor intercept before");
Object object = methodProxy.invokeSuper(obj, args);
System.out.println("CglibInterceptor intercept after");
return object;
}
}
小结:
- 无需代理对象及接口
- 效率比动态代理高,时间花费更大
- 单例对象使用Cglib更合适,反之,使用动态代理
- 无法对final修饰的类进行操作
使用
public class Main {
public static void main(String[] args) {
// write your code here
/**
* 静态代理
*/
Subject subject = new RealSubject();
Proxy proxy = new Proxy(subject);
proxy.execute();
/**
* 动态代理
*/
Subject subjectImpl = new SubjectImpl();
DynamicProxyHandler handler = new DynamicProxyHandler(subjectImpl);
//DynamicProxyHandler handler = new DynamicProxyHandler();
Subject dyProxy = (Subject) java.lang.reflect.Proxy.
newProxyInstance
(
SubjectImpl.class.getClassLoader(),
SubjectImpl.class.getInterfaces(),
handler
);
dyProxy.execute();
// ------------------------------------------(静动态代理-都需要声明接口)---------------------------------------------------------//
/**
* Cglib 代理
*/
CglibInterceptor interceptor = new CglibInterceptor();
SubjectCglib subjectCglib2 =
interceptor.createProxy(SubjectCglib.class);
subjectCglib2.execute();
}
}